24Slides / laravel-saml2

[Laravel 5.4+] An integration to add SSO to your service via SAML2 protocol based on OneLogin toolkit with support of multiple Identity Providers
MIT License
226 stars 69 forks source link

Authentication Persistence #59

Open andreadme opened 1 year ago

andreadme commented 1 year ago

Hello, I have issue regarding the authentication, I logged in using the Event listener "UserLoggedIn". But once I get the Auth::user() in Controller, I'm getting a null value.

I also tried saving the userData in Session but once I try to obtain the value of the Session, I'm getting null. Maybe middleware issue?

I'm using Laravel 8+ and NextJS

UserLoggedIn

<?php

namespace App\Listeners;

use App\Models\User;
use Illuminate\Http\Request;
use Slides\Saml2\Events\SignedIn;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;

class UserLoggedIn
{
    public $request;

    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct(Request $request)
    {
        //
        $this->request = $request;
    }

    /**
     * Handle the event.
     *
     * @param  Slides\Saml2\Events\SignedIn  $event
     * @return void
     */
    public function handle(SignedIn $event)
{
        $messageId = $event->auth->getLastMessageId();
        // your own code preventing reuse of a $messageId to stop replay attacks
        $samlUser = $event->auth->getSaml2User();
        $userData = [
            'id' => $samlUser->getUserId(),
            'attributes' => $samlUser->getAttributes(),
            'assertion' => $samlUser->getRawSamlAssertion()
        ];

        // dd($userData);
        // Login a user.
        // Auth::login($user);
        $searchUser = User::where('email', $userData['attributes']['email'])->first();

        if ($searchUser) {
            Auth::login($searchUser);
        } else {
            $newUser = User::create([
                'name' => $userData['attributes']['first_name'][0],
                'email' => $userData['attributes']['email'][0],
                'role' => 'admin',
                'password' => bcrypt('password')
            ]);

            Auth::login($newUser);
        }
    }
}

Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array<int, class-string|string>
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        // \Illuminate\Session\Middleware\StartSession::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        // \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'saml' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            // \App\Http\Middleware\SAMLAuthenticated::class,
            // \App\Listeners\UserLoggedIn::class,
            // \Slides\Saml2\Events\SignedIn::class,
            // \App\Listeners\UserLoggedIn::class,
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array<string, class-string|string>
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \App\Http\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'auth.saml' => \App\Http\Middleware\SAMLAuthenticated::class,
    ];
}

api.php

<?php

use App\Http\Controllers\AuthController;
use App\Http\Controllers\ContactInfoController;
use App\Http\Controllers\InitiativeController;
use App\Http\Controllers\PageController;
use App\Http\Controllers\PillarController;
use App\Http\Controllers\ProgramController;
use App\Http\Controllers\SDGContributionController;
use App\Http\Controllers\SDGProgressController;
use App\Http\Controllers\SDGStrategyController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

    // Route::middleware('saml')->group(function () {
        Route::post('create-page', [PageController::class, 'store']);
        Route::get('all-pages', [PageController::class, 'showAll']);
        Route::get('single-page/{id}', [PageController::class, 'show']);
        Route::post('edit-page/{id}', [PageController::class, 'update']);
        Route::delete('remove-page/{id}', [PageController::class, 'destroy']);
        Route::post('publish-page/{id}', [PageController::class, 'publish']);

        Route::post('create-sdg-strategy', [SDGStrategyController::class, 'store']);
        Route::get('all-sdg-strategies', [SDGStrategyController::class, 'showAll']);
        Route::get('single-sdg-strategy/{id}', [SDGStrategyController::class, 'show']);
        Route::post('edit-sdg-strategy/{id}', [SDGStrategyController::class, 'update']);
        Route::delete('remove-sdg-strategy/{id}', [SDGStrategyController::class, 'destroy']);

        Route::post('create-sdg-progress', [SDGProgressController::class, 'store']);
        Route::get('all-sdg-progresses', [SDGProgressController::class, 'showAll']);
        Route::get('single-sdg-progress/{id}', [SDGProgressController::class, 'show']);
        Route::post('edit-sdg-progress/{id}', [SDGProgressController::class, 'update']);
        Route::delete('remove-sdg-progress/{id}', [SDGProgressController::class, 'destroy']);

        Route::post('create-pillar', [PillarController::class, 'store']);
        Route::get('all-pillars', [PillarController::class, 'showAll']);
        Route::get('single-pillar/{id}', [PillarController::class, 'show']);
        Route::post('edit-pillar/{id}', [PillarController::class, 'update']);
        Route::delete('remove-pillar/{id}', [PillarController::class, 'destroy']);

        Route::post('create-initiative', [InitiativeController::class, 'store']);
        Route::get('all-initiatives', [InitiativeController::class, 'showAll']);
        Route::get('single-initiative/{id}', [InitiativeController::class, 'show']);
        Route::post('edit-initiative/{id}', [InitiativeController::class, 'update']);
        Route::delete('remove-initiative/{id}', [InitiativeController::class, 'destroy']);

        Route::get('all-contact-infos', [ContactInfoController::class, 'showAll']);
        Route::get('single-contact-info/{id}', [ContactInfoController::class, 'show']);
        Route::post('edit-contact-info/{id}', [ContactInfoController::class, 'update']);

        Route::post('create-program', [ProgramController::class, 'store']);
        Route::get('all-programs', [ProgramController::class, 'showAll']);
        Route::get('single-program/{id}', [ProgramController::class, 'show']);
        Route::post('edit-program/{id}', [ProgramController::class, 'update']);
        Route::delete('remove-program/{id}', [ProgramController::class, 'destroy']);

        // Secured routes go here
        Route::get('test', function(Request $request) {
            Session::put('userData2', 'sample_user26');
            Session::save();
        });

        Route::get('login', function () {
            return response()->json([
                'URL' => 'http://localhost:8000/saml2/51af91b9-b072-4654-9be8-9f947989a879/login',
            ], 200);
        });
        Route::redirect('logout', '/saml2/51af91b9-b072-4654-9be8-9f947989a879/logout')->name('logout');
    // });

    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
        return $request->user();
    });

auth.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'saml' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that each reset token will be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

EventServiceProvider

<?php

namespace App\Providers;

use App\Listeners\UserLoggedIn;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Session;
use Slides\Saml2\Events\SignedIn;
use Slides\Saml2\Events\SignedOut;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        SignedIn::class => [
            UserLoggedIn::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Event::listen(Slides\Saml2\Events\SignedOut::class, function (SignedOut $event) {
            Auth::logout();
            Session::save();
        });
    }

    /**
     * Determine if events and listeners should be automatically discovered.
     *
     * @return bool
     */
    public function shouldDiscoverEvents()
    {
        return true;
    }
}

.env

SANCTUM_STATEFUL_DOMAINS=web.globe-cms.test
SESSION_DOMAIN=.globe-cms.test
andreadme commented 1 year ago

Hello, I have issue regarding the authentication, I logged in using the Event listener "UserLoggedIn". But once I get the Auth::user() in Controller, I'm getting a null value.

I also tried saving the userData in Session but once I try to obtain the value of the Session, I'm getting null. Maybe middleware issue?

UserLoggedIn

<?php

namespace App\Listeners;

use App\Models\User;
use Illuminate\Http\Request;
use Slides\Saml2\Events\SignedIn;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;

class UserLoggedIn
{
    public $request;

    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct(Request $request)
    {
        //
        $this->request = $request;
    }

    /**
     * Handle the event.
     *
     * @param  Slides\Saml2\Events\SignedIn  $event
     * @return void
     */
    public function handle(SignedIn $event)
{
        $messageId = $event->auth->getLastMessageId();
        // your own code preventing reuse of a $messageId to stop replay attacks
        $samlUser = $event->auth->getSaml2User();
        $userData = [
            'id' => $samlUser->getUserId(),
            'attributes' => $samlUser->getAttributes(),
            'assertion' => $samlUser->getRawSamlAssertion()
        ];

        // dd($userData);
        // Login a user.
        // Auth::login($user);
        $searchUser = User::where('email', $userData['attributes']['email'])->first();

        if ($searchUser) {
            Auth::login($searchUser);
        } else {
            $newUser = User::create([
                'name' => $userData['attributes']['first_name'][0],
                'email' => $userData['attributes']['email'][0],
                'role' => 'admin',
                'password' => bcrypt('password')
            ]);

            Auth::login($newUser);
        }
    }
}

Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array<int, class-string|string>
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        // \Illuminate\Session\Middleware\StartSession::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        // \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'saml' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            // \App\Http\Middleware\SAMLAuthenticated::class,
            // \App\Listeners\UserLoggedIn::class,
            // \Slides\Saml2\Events\SignedIn::class,
            // \App\Listeners\UserLoggedIn::class,
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array<string, class-string|string>
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \App\Http\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'auth.saml' => \App\Http\Middleware\SAMLAuthenticated::class,
    ];
}

api.php

<?php

use App\Http\Controllers\AuthController;
use App\Http\Controllers\ContactInfoController;
use App\Http\Controllers\InitiativeController;
use App\Http\Controllers\PageController;
use App\Http\Controllers\PillarController;
use App\Http\Controllers\ProgramController;
use App\Http\Controllers\SDGContributionController;
use App\Http\Controllers\SDGProgressController;
use App\Http\Controllers\SDGStrategyController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

    // Route::middleware('saml')->group(function () {
        Route::post('create-page', [PageController::class, 'store']);
        Route::get('all-pages', [PageController::class, 'showAll']);
        Route::get('single-page/{id}', [PageController::class, 'show']);
        Route::post('edit-page/{id}', [PageController::class, 'update']);
        Route::delete('remove-page/{id}', [PageController::class, 'destroy']);
        Route::post('publish-page/{id}', [PageController::class, 'publish']);

        Route::post('create-sdg-strategy', [SDGStrategyController::class, 'store']);
        Route::get('all-sdg-strategies', [SDGStrategyController::class, 'showAll']);
        Route::get('single-sdg-strategy/{id}', [SDGStrategyController::class, 'show']);
        Route::post('edit-sdg-strategy/{id}', [SDGStrategyController::class, 'update']);
        Route::delete('remove-sdg-strategy/{id}', [SDGStrategyController::class, 'destroy']);

        Route::post('create-sdg-progress', [SDGProgressController::class, 'store']);
        Route::get('all-sdg-progresses', [SDGProgressController::class, 'showAll']);
        Route::get('single-sdg-progress/{id}', [SDGProgressController::class, 'show']);
        Route::post('edit-sdg-progress/{id}', [SDGProgressController::class, 'update']);
        Route::delete('remove-sdg-progress/{id}', [SDGProgressController::class, 'destroy']);

        Route::post('create-pillar', [PillarController::class, 'store']);
        Route::get('all-pillars', [PillarController::class, 'showAll']);
        Route::get('single-pillar/{id}', [PillarController::class, 'show']);
        Route::post('edit-pillar/{id}', [PillarController::class, 'update']);
        Route::delete('remove-pillar/{id}', [PillarController::class, 'destroy']);

        Route::post('create-initiative', [InitiativeController::class, 'store']);
        Route::get('all-initiatives', [InitiativeController::class, 'showAll']);
        Route::get('single-initiative/{id}', [InitiativeController::class, 'show']);
        Route::post('edit-initiative/{id}', [InitiativeController::class, 'update']);
        Route::delete('remove-initiative/{id}', [InitiativeController::class, 'destroy']);

        Route::get('all-contact-infos', [ContactInfoController::class, 'showAll']);
        Route::get('single-contact-info/{id}', [ContactInfoController::class, 'show']);
        Route::post('edit-contact-info/{id}', [ContactInfoController::class, 'update']);

        Route::post('create-program', [ProgramController::class, 'store']);
        Route::get('all-programs', [ProgramController::class, 'showAll']);
        Route::get('single-program/{id}', [ProgramController::class, 'show']);
        Route::post('edit-program/{id}', [ProgramController::class, 'update']);
        Route::delete('remove-program/{id}', [ProgramController::class, 'destroy']);

        // Secured routes go here
        Route::get('test', function(Request $request) {
            Session::put('userData2', 'sample_user26');
            Session::save();
        });

        Route::get('login', function () {
            return response()->json([
                'URL' => 'http://localhost:8000/saml2/51af91b9-b072-4654-9be8-9f947989a879/login',
            ], 200);
        });
        Route::redirect('logout', '/saml2/51af91b9-b072-4654-9be8-9f947989a879/logout')->name('logout');
    // });

    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
        return $request->user();
    });

auth.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'saml' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that each reset token will be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

EventServiceProvider

<?php

namespace App\Providers;

use App\Listeners\UserLoggedIn;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Session;
use Slides\Saml2\Events\SignedIn;
use Slides\Saml2\Events\SignedOut;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        SignedIn::class => [
            UserLoggedIn::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Event::listen(Slides\Saml2\Events\SignedOut::class, function (SignedOut $event) {
            Auth::logout();
            Session::save();
        });
    }

    /**
     * Determine if events and listeners should be automatically discovered.
     *
     * @return bool
     */
    public function shouldDiscoverEvents()
    {
        return true;
    }
}

.env

SANCTUM_STATEFUL_DOMAINS=web.globe-cms.test
SESSION_DOMAIN=.globe-cms.test

I fixed the issue using this line :

// assert cookie or reload current URL
if (! $request->hasHeader('Cookie')) {
    header('Location: '.url()->current());
    exit;
}

inside my api.php

Route::get('user', function(Request $request) {
    // assert cookie or reload current URL
    if (! $request->hasHeader('Cookie')) {
        header('Location: '.url()->current());
        exit;
    }
    dd(Auth::user());
    // return true
});

My reference: https://stackoverflow.com/questions/67692358/losing-session-data-after-post-from-third-party-website