🧠 Tổng quan — JWT là gì?
JWT (JSON Web Token) là một chuẩn mở (RFC 7519) dùng để truyền thông tin an toàn giữa các bên dưới dạng một JSON object được ký số (digitally signed).
Hãy hình dung JWT như một thẻ nhân viên điện tử: thẻ chứa thông tin của bạn (tên, phòng ban, quyền hạn), được công ty ký xác nhận. Bảo vệ ở cửa không cần gọi HR để xác minh — họ chỉ cần kiểm tra chữ ký trên thẻ.
🏗️ Cấu trúc JWT
Một JWT gồm 3 phần, phân tách bằng dấu chấm (.):
xxxxx.yyyyy.zzzzz
│ │ │
Header Payload Signature
1. Header
Chứa loại token và thuật toán ký:
{
"alg": "RS256",
"typ": "JWT"
}
2. Payload (Claims)
Chứa thông tin người dùng và metadata. Lưu ý: phần này chỉ được mã hóa Base64, KHÔNG được mã hóa — bất kỳ ai cũng có thể đọc được.
{
"sub": "user_123",
"name": "Trung Phan",
"role": "admin",
"iat": 1711234567,
"exp": 1711235467
}
| Claim | Ý nghĩa |
|---|---|
sub |
Subject — ID người dùng |
iat |
Issued At — thời điểm tạo token |
exp |
Expiration — thời điểm hết hạn |
role |
Custom claim — quyền hạn người dùng |
3. Signature
Được tạo bằng cách ký Header + Payload với secret key hoặc private key:
RS256(base64(header) + "." + base64(payload), privateKey)
Chữ ký này đảm bảo không ai có thể giả mạo hoặc sửa đổi nội dung token mà không bị phát hiện.
⚙️ Cơ chế hoạt động — Flow xác thực
sequenceDiagram
participant Client as 🖥️ Client (Browser/App)
participant Auth as 🔐 Auth Server
participant API as 📦 Resource Server (API)
Client->>Auth: POST /login (username + password)
Auth->>Auth: Xác minh thông tin đăng nhập
alt ✅ Đăng nhập thành công
Auth->>Auth: Tạo JWT (Header + Payload + Ký số)
Auth-->>Client: 200 OK + Access Token (JWT) + Refresh Token
else ❌ Thất bại
Auth-->>Client: 401 Unauthorized
end
Note over Client: Lưu Access Token (memory/cookie)
Client->>API: GET /api/data\nAuthorization: Bearer eyJhbG...
API->>API: 1. Xác minh chữ ký\n2. Kiểm tra exp (hết hạn chưa?)
alt ✅ Token hợp lệ
API-->>Client: 200 OK + Dữ liệu
else ⏰ Token hết hạn
API-->>Client: 401 Token Expired
Client->>Auth: POST /refresh (Refresh Token)
Auth-->>Client: Access Token mới
end
Giải thích từng bước:
- Đăng nhập: Client gửi username/password → Auth Server xác minh → nếu hợp lệ, tạo JWT và trả về.
- Lưu token: Client lưu Access Token (thường trong memory hoặc
httpOnly cookie). - Gọi API: Mỗi request, Client đính kèm token vào header
Authorization: Bearer <token>. - Xác minh: API Server kiểm tra chữ ký và thời hạn — không cần truy vấn database.
- Làm mới: Khi Access Token hết hạn, dùng Refresh Token để lấy token mới mà không cần đăng nhập lại.
✅ Ưu điểm
- Stateless (không trạng thái): Server không cần lưu session → dễ mở rộng (scale) theo chiều ngang.
- Tự chứa thông tin: Payload chứa đủ thông tin người dùng → giảm truy vấn DB.
- Linh hoạt: Hoạt động tốt với microservices — nhiều service có thể xác minh cùng một token.
- Cross-domain: Dễ dùng trong môi trường CORS, mobile app, SPA.
⚠️ Nhược điểm & Rủi ro cần lưu ý
| Vấn đề | Giải thích | Giải pháp |
|---|---|---|
| Không thu hồi được | Token hợp lệ cho đến khi hết hạn dù user đã logout | Đặt exp ngắn (15–30 phút) + Refresh Token |
| Payload có thể đọc được | Base64 ≠ mã hóa, ai cũng decode được | Không lưu thông tin nhạy cảm (mật khẩu, CCCD…) |
| Kích thước lớn | Payload càng nhiều claims, token càng to | Chỉ lưu claims cần thiết |
| Thuật toán yếu | alg: none hoặc HS256 có thể bị tấn công |
Dùng RS256 hoặc ES256 cho production |
🔐 Best Practices cho Production
- Dùng thuật toán RS256 hoặc ES256 (asymmetric) thay vì HS256
- Access Token hết hạn sau 15–30 phút
- Refresh Token hết hạn sau 7–30 ngày, lưu trong
httpOnly cookie - Không lưu thông tin nhạy cảm trong payload
- Validate đầy đủ: chữ ký +
exp+iss(issuer) +aud(audience) - Implement token rotation: mỗi lần refresh, cấp Refresh Token mới và vô hiệu hóa cái cũ
🔄 Access Token vs Refresh Token
| Access Token | Refresh Token | |
|---|---|---|
| Mục đích | Xác thực mỗi API request | Lấy Access Token mới |
| Thời hạn | Ngắn (15–30 phút) | Dài (7–30 ngày) |
| Nơi lưu | Memory / Authorization header | httpOnly cookie |
| Gửi đến | Resource Server (API) | Auth Server |
| Khi bị lộ | Thiệt hại giới hạn (hết hạn nhanh) | Nguy hiểm hơn — cần revoke ngay |
🆚 So sánh với Session-based Authentication
| Tiêu chí | JWT (Stateless) | Session (Stateful) |
|---|---|---|
| Lưu trữ phía server | ❌ Không cần | ✅ Cần (DB/Redis) |
| Khả năng mở rộng | ✅ Tốt (scale ngang dễ) | ⚠️ Khó hơn (cần shared session store) |
| Thu hồi token | ❌ Khó (cần blacklist) | ✅ Dễ (xóa session) |
| Phù hợp với | Microservices, Mobile, SPA | Web truyền thống, cần logout ngay lập tức |
| Kích thước | Lớn hơn (token trong header) | Nhỏ (chỉ session ID trong cookie) |