Moshe Katz
Moshe Katz

Reputation: 16863

How to log out from Laravel via Sanctum SPA

I have a Vue.js SPA (app.example.com) that communicates with a backend Laravel application (accounts.example.com). Authentication is handled by the Laravel application - if an unauthenticated user visits the SPA, they are redirected to the Laravel app to log in and then redirected back to the SPA.

The Laravel application has a LoginController that is using Laravel's built-in Illuminate\Foundation\Auth\AuthenticatesUsers trait. Logging in works perfectly.

The problem I have is with logging out - I have a "Log out" button in the SPA that needs to log out the Laravel session.

In order to prevent denial-of-service via CSRF, Laravel's default logout route (in routes/web.php -- Route::post('logout', [LoginController::class, 'logout'])) only accepts POST requests, not GET requests. Additionally, the logout POST must contain the CSRF token in the _token field.

By default, I don't have access to the raw CSRF token in the SPA, only the encrypted version provided by /sanctum/csrf-cookie, so I can't just create a form and have Vue.js submit it. I also can't use axios to do the logout for the same reason.

I tried to add another route (in routes/api.php) like this so the same logout function will be called but the api middleware group is applied instead of the web middleware group:

Route::post('/logout', [\App\Http\Controllers\Auth\LoginController::class, 'logout']);

When I call this endpoint, I get an error:

Method Illuminate\Auth\RequestGuard::logout does not exist.

How can I get this logout to work without disabling CSRF protection or enabling GET requets to logout?

Upvotes: 0

Views: 2015

Answers (1)

Moshe Katz
Moshe Katz

Reputation: 16863

I found this discussion in the Laravel Sanctum repository.

Based on that, I changed my route in routes/api.php like this:

Route::post('/logout', [\App\Http\Controllers\Auth\LoginController::class, 'logout'])
    ->middleware('auth:web');

This tells the logout API call use SessionGuard instead of RequestGuard, and resolves the issue.

Upvotes: 2

Related Questions