That tiny "Remember Me" checkbox on login forms seems innocent enough, but it orchestrates a sophisticated security mechanism that keeps users logged in for weeks. How does Laravel maintain authentication across browser restarts without compromising security? Let's uncover the elegant engineering behind remember tokens.
What Is the Remember Me Feature?
The "Remember Me" feature allows users to stay authenticated even after closing their browser or when their session expires. Instead of logging in every time, Laravel automatically re-authenticates them using a long-lived remember token.
// Login form with remember me
<form method="POST" action="/login">
@csrf
<input type="email" name="email">
<input type="password" name="password">
<input type="checkbox" name="remember"> Remember Me
<button type="submit">Login</button>
</form>
// Controller
if (Auth::attempt($credentials, $request->filled('remember'))) {
// User will be remembered
}
That second parameter in Auth::attempt() triggers the remember token mechanism.
How Remember Tokens Are Generated
When you check "Remember Me," Laravel performs additional operations after successful authentication:
Step 1: Generate Random Token
// Behind the scenes during Auth::attempt($credentials, true)
$token = Str::random(60);
Laravel generates a cryptographically secure 60-character random string. This becomes the remember token.
Step 2: Store Token in Database
// Update user's remember_token column
$user->setRememberToken($token);
$user->save();
// Database update
UPDATE users SET remember_token = 'abc123...xyz789' WHERE id = 1;
The users table must have a remember_token column:
// Migration
Schema::table('users', function (Blueprint $table) {
$table->string('remember_token', 100)->nullable();
});
Step 3: Create Long-Lived Cookie
// Behind the scenes
cookie()->queue(
'remember_web_' . sha1(static::class), // Cookie name
$token, // Token value
576000 // 400 days (in minutes)
);
Laravel sends a cookie to the browser that will persist for 400 days. This cookie contains the plain-text remember token.
The Cookie Structure
The remember cookie has specific characteristics:
Set-Cookie: remember_web_abc123=xyz789...;
Max-Age=34560000;
Path=/;
HttpOnly;
Secure;
SameSite=Lax
Cookie attributes:
- Max-Age: 400 days (34,560,000 seconds)
- HttpOnly: JavaScript cannot access it (XSS protection)
- Secure: Only sent over HTTPS in production
- SameSite=Lax: CSRF protection
- Encrypted: Laravel automatically encrypts all cookies
The Auto-Login Flow
When a user returns after their session expired, Laravel automatically re-authenticates them:
Step 1: Session Check
// On incoming request, check for active session
$userId = session()->get('login_web_' . sha1('session'));
if ($userId) {
// User has active session, load from session
return User::find($userId);
}
If no active session exists, Laravel checks for remember cookie.
Step 2: Remember Cookie Check
// Behind the scenes in auth middleware
$rememberCookie = $request->cookie('remember_web_' . sha1('session'));
if ($rememberCookie) {
// Try to authenticate using remember token
}
Step 3: Token Validation
Laravel queries the database to find a user with matching remember token:
// Behind the scenes
$user = User::where('remember_token', $rememberCookie)->first();
if ($user) {
// Token matches, user found
}
This is a direct database lookup—no hashing involved. The token in the cookie matches the token in the database exactly.
Step 4: Create New Session
Once validated, Laravel creates a fresh session:
// Behind the scenes
session()->put('login_web_' . sha1('session'), $user->id);
session()->migrate(); // New session ID for security
// User is now authenticated
Auth::setUser($user);
The user is seamlessly re-authenticated without entering credentials.
Step 5: Cycle Remember Token
For security, Laravel generates a new remember token:
// Behind the scenes
$newToken = Str::random(60);
$user->setRememberToken($newToken);
$user->save();
// Update cookie with new token
cookie()->queue('remember_web_' . sha1('session'), $newToken, 576000);
This token rotation prevents replay attacks if an old token is stolen.
Security Mechanisms
Token Rotation on Every Login
Every time the remember token is used for authentication, Laravel generates a new one:
// Old token becomes invalid immediately
// New token is issued
// Timeline:
// Day 1: Token A created, stored in cookie
// Day 10: User returns, Token A validates
// Day 10: Token B generated, replaces Token A
// Day 10: Token A no longer works
This limits the window of opportunity if a token is compromised.
Single Device Limitation
Remember tokens are device-specific:
// User logs in on laptop with "Remember Me"
// Laptop gets token: abc123...
// User logs in on phone with "Remember Me"
// Phone gets NEW token: xyz789...
// Laptop's token (abc123) is now INVALID
Each new "Remember Me" login invalidates previous tokens. Only the most recent device stays remembered.
No Token Sharing
Unlike session IDs, remember tokens cannot be shared between devices:
// If you copy the remember cookie to another device
// First device to use it gets re-authenticated
// Second device fails because token was already cycled
HttpOnly Cookie Protection
JavaScript cannot access remember cookies:
// This returns nothing for remember cookie
document.cookie; // remember_web_* is hidden
// XSS attacks cannot steal remember tokens
Remember Token vs Session
Understanding the differences helps clarify when each is used:
Session Authentication
// Short-lived (default: 120 minutes)
'lifetime' => 120,
// Server-side storage
session()->put('user_id', 1);
// Expires when browser closes (if configured)
'expire_on_close' => true,
Remember Token Authentication
// Long-lived (400 days)
$cookieLifetime = 576000; // minutes
// Both client and server storage
// Cookie: plain token
// Database: matching token
// Survives browser restarts
Implementing Remember Me Correctly
Backend Implementation
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
$remember = $request->filled('remember');
if (Auth::attempt($credentials, $remember)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'email' => 'Invalid credentials',
]);
}
Frontend Implementation
<form method="POST" action="{{ route('login') }}">
@csrf
<div>
<label>Email</label>
<input type="email" name="email" required>
</div>
<div>
<label>Password</label>
<input type="password" name="password" required>
</div>
<div>
<label>
<input type="checkbox" name="remember">
Remember Me
</label>
</div>
<button type="submit">Login</button>
</form>
Logout and Remember Token Invalidation
When users log out, remember tokens are invalidated:
public function logout(Request $request)
{
// Get current user
$user = Auth::user();
// Invalidate remember token
$user->setRememberToken(Str::random(60));
$user->save();
// Standard logout
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
The remember cookie becomes useless because the database token no longer matches.
Customizing Remember Duration
You can customize how long users are remembered:
// In AuthServiceProvider boot method
public function boot()
{
// Change remember duration to 30 days
Auth::setDefaultDriver('web');
Auth::shouldUse('web');
// Modify in your authentication logic
$cookieLifetime = 43200; // 30 days in minutes
}
Or create a custom guard with different settings:
// config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'long_term' => [
'driver' => 'session',
'provider' => 'users',
// Custom remember duration can be handled in controller
],
],
Common Pitfalls and Solutions
Pitfall 1: Missing remember_token Column
// Error: Column not found: remember_token
// Solution: Run migration
Schema::table('users', function (Blueprint $table) {
$table->string('remember_token', 100)->nullable();
});
Pitfall 2: Cookie Not Persisting
// Problem: Cookie expires on browser close
// Check session config
// config/session.php
'lifetime' => 120,
'expire_on_close' => false, // Should be false
Pitfall 3: Token Not Cycling
// Laravel handles this automatically
// But if manually implementing, don't forget:
$user->setRememberToken(Str::random(60));
$user->save();
Security Best Practices
1. Always Use HTTPS
// Force HTTPS in production
if (app()->environment('production') && !request()->secure()) {
return redirect()->secure(request()->getRequestUri());
}
Remember tokens sent over HTTP can be intercepted.
2. Implement "Logout All Devices"
public function logoutAllDevices(Request $request)
{
// Cycle remember token (invalidates all remembered devices)
$user = $request->user();
$user->setRememberToken(Str::random(60));
$user->save();
// Logout current session
Auth::logout();
return redirect('/login')
->with('status', 'Logged out from all devices');
}
3. Add Activity Tracking
// Track when remember tokens are used
Schema::table('users', function (Blueprint $table) {
$table->timestamp('last_login_at')->nullable();
$table->string('last_login_ip')->nullable();
});
// Update on auto-login
$user->last_login_at = now();
$user->last_login_ip = request()->ip();
$user->save();
4. Set Reasonable Expiration
// 400 days is Laravel's default
// Consider shorter for sensitive applications:
// 30 days for normal applications
$cookieLifetime = 43200;
// 7 days for financial applications
$cookieLifetime = 10080;
Performance Considerations
Remember token authentication adds minimal overhead:
// Auto-login process:
// 1. Cookie read (browser-side, instant)
// 2. Database SELECT by remember_token (indexed, ~5-10ms)
// 3. Session creation (standard session write)
// 4. Database UPDATE new remember_token (~5-10ms)
// Total added overhead: ~10-20ms
Ensure remember_token column is indexed for faster lookups:
Schema::table('users', function (Blueprint $table) {
$table->index('remember_token');
});
Conclusion
Laravel's "Remember Me" feature is a masterclass in balancing convenience with security. Through token rotation, single-device limitation, and HttpOnly cookies, it keeps users authenticated for weeks while maintaining robust security.
Understanding remember tokens helps you implement persistent authentication correctly and debug issues when users report unexpected logouts or remember me failures.
Building Laravel applications with advanced authentication needs? At NeedLaravelSite, we specialize in Laravel security implementations and application migrations from version 7 to 12. From custom authentication flows to multi-device management, we build secure, user-friendly authentication systems.