Luồng đầy đủ: POST /login xác thực credentials, ký hai token, trả access token trong response body và refresh token trong httpOnly cookie.
js
const accessToken = jwt.sign({ sub: user.id, role: user.role }, secret, { expiresIn: '15m' })
const refreshToken = jwt.sign({ sub: user.id }, refreshSecret, { expiresIn: '7d' })
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
})
res.json({ accessToken })Middleware xác thực đọc token từ header và bắt buộc chốt thuật toán:
js
const token = req.headers.authorization?.split(' ')[1]
req.user = jwt.verify(token, secret, { algorithms: ['HS256'] })- httpOnly cookie chặn được XSS đọc token (nhưng cần chống CSRF); localStorage tiện hơn nhưng XSS lấy được — cookie httpOnly là best practice cho web app.
- Refresh token rotation: mỗi lần dùng refresh token thì phát cặp mới và vô hiệu token cũ; lưu hash của refresh token trong DB để revoke được. POST /refresh đọc cookie, verify rồi trả access token mới; POST /logout xoá cookie và blacklist refresh token.
Lưu ý: không chốt algorithms khi verify thì attacker đổi header sang alg: none và tự ký token.