Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jeroenvip's avatar

Enable login on a second domain for a single application, looking for some feedback

Hello,

Thank you for your time. I am a novice Laravel developer seeking advice on sharing login information on a secondary FQDN for a single Laravel application.

I have devised the following solution (excluding Laravel Sanctum, which I am not yet familiar with). I would like to ascertain if this practice is common and adheres to security measures such as CSRF.

Please note that all domains stored within the application can be designated as secure, as they are all hosted on the same server.

Any tips or suggestions are welcome.

Main domain NGINX

Second domain NGINX

AppServiceProvider

<?php

namespace App\Providers;

use App\Services\OriginService;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;

/**
 * Class AppServiceProvider
 * @package App\Providers
 */
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any app services.
     */
    public function register(): void
    {
    }

    /**
     * Bootstrap any app services.
     */
    public function boot(): void
    {
         OriginService::validateOrigin(request());
    }
}

OriginService

<?php

namespace App\Services;

use App\Models\Origin;
use Illuminate\Http\Request;

/**
 * Class OriginService
 * @package App\Services
 */
class OriginService
{
    /**
     * @param Request $request
     * @return void
     */
    public static function validateOrigin(Request $request): void
    {
        $origins = Origin::where(['url' => $request->getHost()])->exists();

        // Origin doesn't exist
        if (!$origins) {
            return;
        }

        config(['session.domain' => $request->getHost()]);
    }
}

Web route

Route::get('/auth/login', [SessionController::class, 'create'])->name('login');
Route::post('/auth/login', [SessionController::class, 'store'])->middleware('throttle:20,1');
Route::post('/auth/logout', [SessionController::class, 'destroy']);

Blade login view

<h1 class="fs-2 my-2 text-center">{{ __('messages.login') }}</h1>
<form method="POST" action="/auth/login">
    @csrf
    <div class="bg-body-tertiary p-4 rounded-2 border border-gray-300">
        <x-language-selection-form></x-language-selection-form>
        <x-form-input class="mt-2" name="username" label="{{ __('messages.username') }}" value="{{ old('username') }}"
                      required></x-form-input>
        <x-form-error class="mt-2" name="username"></x-form-error>
        <x-form-input class="mt-2" name="password" type="password" label="{{ __('messages.password') }}"
                      required></x-form-input>
        <x-form-error class="mt-2" name="password"></x-form-error>
        <div class="form-check mt-2">
            <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
            <label class="form-check-label" for="remember">{{ __('messages.remember_me') }}</label>
        </div>
        {{-- Add the return url after the login if this is set --}}
        @if(request()->has('return_url'))
            <input type="hidden" name="return_url" value="{{ request()->get('return_url') }}">
        @endif
        <div class="text-end">
            <x-button class="mt-2" type="submit">{{ __('messages.login') }}</x-button>
            <x-link class="mt-2"
                    href="/auth/forgot-password?lang={{ request()->query('lang', 'en') }}">{{ __('messages.forgot_password') }}</x-link>
        </div>
    </div>
</form>
0 likes
2 replies
LaryAI's avatar

Certainly! Here’s a review and some suggestions for your approach to enabling login on a second domain for a single Laravel application.


1. Nginx Configuration

Your Nginx config is mostly correct: both domains point to the same Laravel app directory. This is a common approach for multi-domain apps.

Tip:
In your second domain’s Nginx config, you have:

server_name www.www.domain1.com;

This should probably be:

server_name www.domain2.com;

Otherwise, requests to www.domain2.com won’t match this server block.


2. Session Domain Handling

You’re dynamically setting the session domain in your OriginService. This is a good idea, but there are some caveats:

  • Laravel’s session cookie domain is set when the response is created. Changing it at runtime via config(['session.domain' => ...]) works, but it must be set before any session is started or cookies are sent.
  • Session sharing between domains:
    • If you want users to be logged in on both domains with a single login, you must set the session cookie domain to a common parent domain (e.g., .domain1.com), and both domains must be subdomains of that parent.
    • If domain1.com and domain2.com are entirely separate, browsers will not share cookies between them for security reasons.
    • If you only want users to be logged in on the domain they use, your approach is fine.

3. CSRF Protection

Laravel’s CSRF protection works per domain, as the CSRF token is stored in the session. As long as your session is working per domain, CSRF protection will work as expected.


4. Security

  • Validate allowed domains: You’re already checking the host against your Origin model. This is good.
  • HTTPS: Both domains are using HTTPS, which is essential for session security.
  • CORS: If you plan to make cross-domain AJAX requests, you’ll need to configure CORS properly.

5. Alternative: Laravel Sanctum

If you ever need true cross-domain authentication (e.g., SPA on one domain, API on another), Laravel Sanctum is the recommended approach. For now, your approach is fine for traditional web apps.


6. Summary

  • Your approach is valid for separate logins per domain.
  • Session sharing between totally different domains is not possible due to browser security.
  • Make sure your Nginx server_name is correct for each domain.
  • Set the session domain before the session starts (ideally in a middleware that runs before the session is started).

Example: Middleware for Session Domain

Instead of doing this in AppServiceProvider, consider a middleware:

php artisan make:middleware SetSessionDomain
// app/Http/Middleware/SetSessionDomain.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use App\Models\Origin;

class SetSessionDomain
{
    public function handle(Request $request, Closure $next)
    {
        if (Origin::where('url', $request->getHost())->exists()) {
            config(['session.domain' => $request->getHost()]);
        }

        return $next($request);
    }
}

Register this middleware in app/Http/Kernel.php under web middleware group, before the StartSession middleware.


Conclusion

  • Your approach is secure and common for multi-domain apps on the same codebase.
  • You cannot share sessions between unrelated domains due to browser restrictions.
  • Consider using middleware for setting session domain.
  • If you need cross-domain authentication, look into Laravel Sanctum.

Let me know if you have any follow-up questions!

Mega_Aleksandar's avatar

Hi there,

Why not use a single database on the "primary" server, make the session driver the database (not the file) and point the other server to it? I mean, sure, files live on both servers, you'll need to update both codebases, but it is still a single database, so single login point and check.

Correct me if I am wrong here guys.

Best of luck...

Please or to participate in this conversation.