Access token ngắn hạn (15 phút), gửi kèm mọi request, stateless nên server không lưu gì. Refresh token dài hạn (7-30 ngày), nằm trong httpOnly cookie, và chỉ dùng ở đúng một chỗ là endpoint /auth/refresh để đổi lấy access token mới.
- Rotation: mỗi lần dùng refresh token phải phát cặp token mới và huỷ token cũ (one-time-use). Thấy token cũ được dùng lại nghĩa là nó đã bị đánh cắp — revoke sạch cả session.
- Blacklist: lưu JTI (JWT ID) đã revoke vào Redis với TTL đúng bằng thời gian sống còn lại của token, rồi kiểm tra trong auth middleware.
- Sliding session: mỗi request hợp lệ thì gia hạn — còn dưới 1 ngày thì phát refresh token mới.
- Bảo mật: lưu hash của refresh token trong DB thay vì lưu nguyên chuỗi; DB có lộ thì token cũng vô dụng.
Lưu ý: không làm rotation thì refresh token bị trộm dùng được tới tận lúc hết hạn; không để trong httpOnly cookie thì XSS lấy mất.