Mỗi cách lưu token cân giữa ba tính chất và chỉ đạt tối đa 2/3:
1. XSS-resistant — JS không đọc được token.
2. JS-accessible — JS đọc được để tự gắn header Authorization.
3. CSRF-resistant — không bị tự gửi kèm trong request cross-site.
Ma trận trade-off:
localStorage: JS-accessible + CSRF-resistant, nhưng KHÔNG XSS-resistant — một script XSS đọc được token và replay từ nơi khác.- Cookie
HttpOnly: XSS-resistant, nhưng JS không đọc được (không tự gắnAuthorizationđược) và dễ CSRF vì trình duyệt tự đính kèm — phải bù bằngSameSite/anti-CSRF token. - In-memory (biến/closure JS): JS-accessible + CSRF-resistant; XSS về lý thuyết vẫn với tới nhưng token biến mất khi reload nên cửa sổ tấn công hẹp — đổi lại UX phải khôi phục phiên sau mỗi lần reload.
Vì không phương án nào đạt 3/3, thiết kế thực tế luôn là tổ hợp nhiều nơi lưu + biện pháp bù cho điểm yếu của từng nơi (khuyến nghị cụ thể ở câu "lưu token ở đâu").