skip to content

In Laravel, what should a logout action do besides calling Auth::logout(), and what do invalidate() and regenerateToken() each add?

level: middleimportance: must knowfreq 60%

answer

  1. logout only touches the guard's keys
  2. remember_token cycled, cookie forgotten
  3. invalidate: flush plus new ID
  4. flush drops the CSRF token too
  5. logout over POST, not GET

basics

~20 s

Auth::logout() removes the guard's user from the session, forgets the remember-me cookie and cycles remember_token. Then invalidate() wipes all session data under a new ID, and regenerateToken() issues a fresh CSRF token, so nothing from the old session survives.

solid answer

~50 s

`Auth::logout()` on the session guard removes the `login_web_<hash>` key, queues a forget for the remember-me cookie, and, if the user has a `remember_token`, replaces it with a new random value, which kills remember-me cookies on every device. It fires `Logout` and marks the guard logged out. It does **not** clear the rest of the session: the intended URL, flash data and anything else the app stored remain. So the documented logout also calls `$request->session()->invalidate()`, which flushes every attribute and migrates to a new ID with the old record destroyed, and `$request->session()->regenerateToken()`, which puts a fresh `_token` back, because the flush removed the CSRF token. On a shared kiosk this is what stops the next member inheriting anything from the previous one. Expose logout as a `POST` route so a cross-site link cannot sign people out. `Auth::logoutCurrentDevice()` is the variant that leaves `remember_token` alone.

code

php · 15 lines
php
<?php

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

Route::post('/logout', function (Request $request): RedirectResponse {
    Auth::logout();

    $request->session()->invalidate();
    $request->session()->regenerateToken();

    return redirect('/');
})->middleware('auth')->name('logout');

go deeper

for a junior

Remember the three lines of a Laravel logout: Auth::logout(), then invalidate() and regenerateToken() on the session, behind a POST route.

for a middle

Explain what each call removes or adds: guard key and remember cookie, all session data with a new ID, and a fresh CSRF token after the flush.

for a senior

Reason about shared devices, remember-me on other devices via remember_token cycling, and when logoutCurrentDevice() is the better choice.

for a principal

Set the organisation's sign-out guarantees for shared terminals, combining idle timeouts, no remember-me and auditable Logout events.

## Three separate jobs Signing someone out in Laravel touches three things that live in different places: 1. the **guard's record** that a user is signed in, 2. the **rest of the session**, everything else the app stored for that browser, 3. the **CSRF token**, which also lives in the session. `Auth::logout()` handles only the first. The documented pattern adds one call for each of the others. ## What `Auth::logout()` does On `Illuminate\Auth\SessionGuard` in Laravel 13: - removes the guard's session key (`login_web_` plus a hash of the guard class); - un-queues any remember-me cookie queued earlier in the request, and if the request carried one, queues a **forget** cookie for it; - if the user has a non-empty `remember_token`, **cycles** it to a new 60-character random string and saves it, so every remember-me cookie issued before, on any device, stops working; - dispatches the `Illuminate\Auth\Events\Logout` event; - clears the cached user and marks the guard as logged out for the rest of the request. It leaves every other session attribute in place. ## `invalidate()` `$request->session()->invalidate()` calls `flush()`, which empties **all** session attributes, and then `migrate(true)`, which assigns a **new session ID** and **destroys the old record** in the session store. Anything that could leak from one person to the next goes: the intended URL, old form input, flash messages, a half-built booking. ## `regenerateToken()` Because `flush()` removed the `_token` attribute, the session no longer holds a CSRF token. `$request->session()->regenerateToken()` puts a fresh random one in, so: - the login form rendered after the redirect gets a valid token; - a token captured from the old page cannot be replayed against the new session. ## Putting it together | Call | Removes | Adds | |---|---|---| | `Auth::logout()` | guard user key, remember cookie | new `remember_token` in the database | | `session()->invalidate()` | every session attribute, old session record | new session ID | | `session()->regenerateToken()` | nothing | new CSRF token | ## The kiosk angle A shared gym kiosk is the case where a sloppy logout shows. If the controller only calls `Auth::logout()`, the next member at the screen inherits the same session ID and can still see the previous member's flash message or intended URL. Pair the full logout with: - no remember-me option on the kiosk login at all; - a short `SESSION_LIFETIME` and an idle timer in the page that posts to the logout route; - a `POST` logout route inside the `web` group, so the CSRF check applies. ## `logout()` versus `logoutCurrentDevice()` `Auth::logoutCurrentDevice()` does the same session and cookie clean-up but **does not cycle** `remember_token` and fires `CurrentDeviceLogout` instead. Use it when signing out here should not end remember-me on the member's phone. For the kiosk, the plain `logout()` is the safer default. ## Multiple guards `invalidate()` empties the whole session, so if one browser is signed into two session guards, a full logout ends both guards' session sign-ins. A remember-me cookie belonging to the other guard is not forgotten, though, so that guard could restore its user from the cookie; on a shared device, call `logout()` on each guard.

  • Why does Auth::logout() on a laptop also end a remember-me session on the user's phone?
    Logout cycles the user's `remember_token` to a new random value in the database. The phone's remember-me cookie still carries the old token, so `retrieveByToken()` finds no match the next time the phone's session expires. Use `Auth::logoutCurrentDevice()` to sign out without cycling the token.
  • What goes wrong if logout calls invalidate() but not regenerateToken()?
    `invalidate()` flushes every attribute, including `_token`, so the session has no CSRF token until one is generated. Calling `regenerateToken()` puts a fresh one in explicitly, so the next form has a valid token and the old page's token can never be replayed.

saying these in an interview costs you the question

  • Auth::logout() destroys the whole session, so nothing else is needed.
  • invalidate() keeps the same session ID and only clears the user.
  • Logout can safely be a GET link in the navigation bar.
  • Auth::logout() leaves remember-me cookies on other devices working.
  • regenerateToken() logs the user out on its own.