5月28日 00:41

How to implement "remember me" functionality using Cookies? What security issues need attention?

Implementing the "remember me" functionality using Cookies requires consideration of security, user experience, and persistent storage.

"Remember me" functionality principle

  • Generate a long-lived authentication token after successful user login
  • Store the token in a persistent Cookie
  • Automatically use the token in the Cookie to complete login when the user visits again

Implementation solutions

Solution 1: Persistent Session Cookie

javascript
// Server-side setting (Node.js Express) function setRememberMeCookie(res, token, rememberMe) { const options = { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', path: '/' }; if (rememberMe) { // Long-term Cookie: 30 days options.maxAge = 30 * 24 * 60 * 60; } else { // Session Cookie: deleted when browser closes options.maxAge = null; } res.cookie('authToken', token, options); }

Solution 2: Dual token mechanism

javascript
// Generate access token and refresh token function generateTokens(userId) { const accessToken = jwt.sign( { userId }, process.env.JWT_SECRET, { expiresIn: '15m' } // Short-term validity ); const refreshToken = crypto.randomBytes(32).toString('hex'); // Store refresh token in database db.saveRefreshToken(userId, refreshToken, { expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) }); return { accessToken, refreshToken }; } // Set Cookies function setAuthCookies(res, tokens, rememberMe) { // Access token: short-term, HttpOnly res.cookie('accessToken', tokens.accessToken, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 15 * 60 // 15 minutes }); // Refresh token: long-term, HttpOnly if (rememberMe) { res.cookie('refreshToken', tokens.refreshToken, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 30 * 24 * 60 * 60 // 30 days }); } }

Security best practices

  1. Token generation
javascript
// Use cryptographically secure random number generator const crypto = require('crypto'); function generateSecureToken() { return crypto.randomBytes(32).toString('hex'); }
  1. Token storage
javascript
// Database storage solution const refreshTokenSchema = new Schema({ userId: { type: ObjectId, required: true }, token: { type: String, required: true, unique: true }, createdAt: { type: Date, default: Date.now }, expiresAt: { type: Date, required: true }, lastUsedAt: { type: Date, default: Date.now }, userAgent: String, ipAddress: String });
  1. Token verification
javascript
async function verifyRefreshToken(token, req) { const record = await db.findRefreshToken(token); if (!record) { throw new Error('Invalid token'); } if (record.expiresAt < new Date()) { await db.deleteRefreshToken(token); throw new Error('Token expired'); } // Optional: verify User-Agent and IP if (record.userAgent !== req.headers['user-agent']) { await db.deleteRefreshToken(token); throw new Error('Token compromised'); } // Update last used time await db.updateRefreshToken(token, { lastUsedAt: new Date() }); return record.userId; }

User experience optimization

  1. Login form
html
<form id="loginForm"> <input type="text" name="username" placeholder="Username" required> <input type="password" name="password" placeholder="Password" required> <label> <input type="checkbox" name="rememberMe"> Remember me (auto-login within 30 days) </label> <button type="submit">Login</button> </form>
  1. Auto-login flow
javascript
// Check Cookie on page load async function checkAutoLogin() { const refreshToken = getCookie('refreshToken'); if (refreshToken) { try { const response = await fetch('/api/auth/refresh', { method: 'POST', credentials: 'include' }); if (response.ok) { const { accessToken } = await response.json(); localStorage.setItem('accessToken', accessToken); // Redirect to home page window.location.href = '/dashboard'; } } catch (error) { console.error('Auto login failed:', error); } } }

Security enhancements

  1. Token rotation
javascript
// Generate new refresh token each time refresh token is used async function rotateRefreshToken(oldToken) { const userId = await verifyRefreshToken(oldToken, req); // Delete old token await db.deleteRefreshToken(oldToken); // Generate new token const newToken = generateSecureToken(); await db.saveRefreshToken(userId, newToken, { expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) }); return newToken; }
  1. Revocation mechanism
javascript
// Revoke all tokens when user logs out async function logoutAllDevices(userId) { await db.deleteAllRefreshTokens(userId); res.clearCookie('accessToken'); res.clearCookie('refreshToken'); }
  1. Device management
javascript
// Display list of logged-in devices async function getActiveDevices(userId) { const tokens = await db.findRefreshTokensByUser(userId); return tokens.map(token => ({ device: parseUserAgent(token.userAgent), lastUsed: token.lastUsedAt, current: token.userAgent === req.headers['user-agent'] })); }
标签:Cookie