Bài viết này liên quan đến API là gì và SSH Key — các khái niệm quan trọng trong bảo mật và authentication.
Opaque Token là gì
Opaque Token là một chuỗi ký tự ngẫu nhiên, không thể đọc được (opaque = mờ, không trong suốt). Client nhận được token này sau khi login thành công, nhưng bản thân token không chứa thông tin gì về user — nó chỉ là một “thẻ hội viên” để server nhận biết.
<code># Ví dụ Opaque Token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c # Token này có vẻ giống JWT, nhưng thực ra là random string # Attempt decode sẽ không ra gì có nghĩa</code>
Đặc điểm quan trọng: server phải lưu trạng thái (stateful). Mỗi khi client gửi opaque token lên, server phải hỏi lại authorization server để xác nhận token còn hợp lệ không, user nào, có quyền gì.
Ưu điểm của Opaque Token
- Bảo mật cao — token không chứa thông tin gì, kể cả hacker lấy được token cũng không đọc được nội dung
- Dễ revoke — vì server lưu trạng thái, có thể revoke token ngay lập tức khi cần (logout, phát hiện xâm nhập)
- Kích thước nhỏ — chỉ là random string, không phình to như JWT có header + payload + signature
Nhược điểm của Opaque Token
- Stateful — server phải duy trì database/token store để verify token
- Tốn hiệu năng — mỗi request đều phải gọi introspection endpoint để verify
- Phụ thuộc authorization server — nếu server down, không verify được token
JWT là gì
JWT (JSON Web Token) là token tự chứa thông tin (self-contained). Nó có cấu trúc gồm 3 phần, mỗi phần được mã hóa Base64URL:
<code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c |_________header__________|.________payload__________|.|_______signature_______|</code>
Cấu trúc JWT
- Header — chứa algorithm (HS256, RS256) và loại token (JWT)
- Payload — chứa claims (sub, name, role, exp, iat…) — thông tin user
- Signature — chữ ký số để xác minh token không bị sửa
<code># Header (decode Base64URL)
{"alg":"HS256","typ":"JWT"}
# Payload (decode Base64URL)
{
"sub": "1234567890", # user ID
"name": "John Doe",
"role": "admin",
"iat": 1516239022, # issued at
"exp": 1516242622 # expiration (15 phút)
}
# Signature = HMAC_SHA256(header.payload, secret_key)</code>
Ưu điểm của JWT
- Stateless — không cần server lưu trạng thái, chỉ cần verify signature là đủ
- Cross-service — nhiều service khác nhau đều verify được token bằng public key
- Chuẩn RFC 7519 — widely supported, interoperable
- Extensible — có thể thêm custom claims tùy ý
Nhược điểm của JWT
- Không revoke được dễ dàng — token hết hạn mới hết hiệu lực, không thể revoke sớm hơn
- Phơi bày thông tin — payload chỉ được encode chứ không mã hóa, ai có token cũng đọc được claims
- Kích thước lớn hơn — header + payload + signature dài hơn opaque token
- Revocation phức tạp — cần token blacklist hoặc short expiration để giảm rủi ro
So sánh Opaque Token và JWT
| Tiêu chí | Opaque Token | JWT |
|---|---|---|
| Thông tin trong token | Không có (random string) | Có (header + payload + signature) |
| Server state | Stateful (cần lưu) | Stateless (không cần lưu) |
| Validation | Gọi introspection endpoint | Verify signature locally |
| Revocation | Dễ dàng, ngay lập tức | Phức tạp (cần blacklist hoặc short TTL) |
| Kích thước | Nhỏ (random string) | Lớn hơn (3 phần Base64) |
| Bảo mật | Cao — không đọc được nội dung | Trung bình — payload visible (nhưng signature đảm bảo integrity) |
| Hiệu năng | Thấp hơn — cần gọi API verify | Cao — verify local, không gọi API |
| Cross-service | Khó — cần shared token store | Dễ — chỉ cần public key |
| Use case phù hợp | Single service, bảo mật cao | Microservices, distributed systems |
| Chuẩn | Không có chuẩn cụ thể | RFC 7519 (JWS, JWE) |
Luồng validation — khác biệt thực tế
Validate Opaque Token
Với Opaque Token, mỗi request đều phải gọi authorization server để verify:
<code>1. Client gửi request kèm token
Authorization: Bearer abc123xyz
2. Resource Server gọi introspection endpoint
POST /oauth/introspect
Content-Type: application/x-www-form-urlencoded
token=abc123xyz
3. Authorization Server kiểm tra database
→ Token còn hợp lệ? → User nào? → Quyền gì?
4. Authorization Server trả về
{"active": true, "sub": "user123", "scope": "read write"}
5. Resource Server mới xử lý request</code>
Validate JWT
Với JWT, resource server verify trực tiếp bằng signature — không cần gọi API:
<code>1. Client gửi request kèm JWT Authorization: Bearer eyJhbGciOiJIUzI1NiIs... 2. Resource Server decode JWT → Lấy header, payload, signature 3. Resource Server verify signature bằng public key HMAC_SHA256(header.payload, secret_or_public_key) 4. Nếu signature hợp lệ → đọc claims từ payload → sub: user123, role: admin, exp: 1735689600 5. Resource Server xử lý request (không gọi API nào)</code>
Khi nào nên dùng Opaque Token
- Hệ thống monolithic đơn giản — không cần cross-service authentication
- Yêu cầu bảo mật cao — không muốn expose bất kỳ thông tin user nào trong token
- Cần revoke token ngay lập tức — logout, phát hiện xâm nhập, thay đổi quyền
- Single sign-on (SSO) enterprise — nhiều ứng dụng cùng dùng chung authorization server
- Compliance nghiêm ngặt — không muốn token tồn tại lâu hơn cần thiết
OAuth 2.0 mặc định dùng opaque token cho access token. Google, Facebook, GitHub đều trả opaque token khi bạn authorize qua OAuth.
Khi nào nên dùng JWT
- Microservices architecture — nhiều service cần verify token độc lập
- Stateless API — không muốn maintain session store
- Third-party API access — cần token chứa thông tin để service khác đọc
- High-performance — không muốn tốn latency gọi introspection API
- API Gateway — verify token rồi forward request đến backend service
Nhiều hệ thống dùng hybrid approach: access token là JWT (stateless, short-lived), refresh token là opaque token (revocable, long-lived).
Triển khai ví dụ
Tạo JWT với Python
<code># Cài thư viện: pip install pyjwt
import jwt
import datetime
secret_key = "your-secret-key"
user_id = "user123"
role = "admin"
payload = {
"sub": user_id,
"role": role,
"iat": datetime.datetime.utcnow(),
"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
}
token = jwt.encode(payload, secret_key, algorithm="HS256")
print(token)
# Verify JWT
try:
decoded = jwt.decode(token, secret_key, algorithms=["HS256"])
print(f"User: {decoded['sub']}, Role: {decoded['role']}")
except jwt.ExpiredSignatureError:
print("Token expired!")
except jwt.InvalidTokenError:
print("Invalid token!")</code>
Tạo Opaque Token với Redis
<code>import redis
import secrets
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def create_opaque_token(user_id, role):
token = secrets.token_urlsafe(32) # Random 32-byte string
# Lưu vào Redis với TTL
token_data = json.dumps({
"user_id": user_id,
"role": role,
"created_at": datetime.datetime.utcnow().isoformat()
})
r.setex(f"token:{token}", 3600, token_data) # Hết hạn sau 1 giờ
return token
def validate_opaque_token(token):
data = r.get(f"token:{token}")
if data:
return json.loads(data)
return None
# Sử dụng
token = create_opaque_token("user123", "admin")
print(f"Token: {token}")
# Verify
user_data = validate_opaque_token(token)
if user_data:
print(f"User: {user_data['user_id']}, Role: {user_data['role']}")
# Revoke token
r.delete(f"token:{token}")</code>
Best practices khi dùng token
- Access token ngắn hạn — 5-15 phút. Refresh token dài hơn (vài ngày đến vài tuần)
- Luôn dùng HTTPS — không gửi token qua HTTP thường
- Không lưu token trong localStorage — dùng httpOnly cookie thay thế
- Refresh token nên là Opaque — dễ revoke, bảo mật hơn
- Implement token rotation — refresh token thì revoke token cũ
- Rate limiting trên auth endpoints — tránh brute force token
<code># Hybrid approach - best of both worlds
# Access Token: JWT (stateless, short-lived)
access_token = jwt.encode({
"sub": user_id,
"exp": datetime.datetime.utcnow() + timedelta(minutes=15)
}, secret, algorithm="HS256")
# Refresh Token: Opaque (revocable, long-lived)
refresh_token = secrets.token_urlsafe(32)
redis.setex(f"refresh:{refresh_token}", timedelta(days=7), user_id)</code>
Câu hỏi thường gặp
Token nào an toàn hơn?
Không có câu trả lời tuyệt đối. Opaque token bảo mật hơn về mặt thông tin (không đọc được gì), nhưng JWT linh hoạt hơn về kiến trúc. Quan trọng là cách bạn implement và quản lý token lifecycle.
Có thể revoke JWT không?
Có, nhưng cần thêm cơ chế: token blacklist trong Redis, hoặc dùng very short expiration (5 phút). Nếu cần revoke ngay, nên dùng opaque token hoặc kết hợp cả hai.
OAuth 2.0 dùng token nào?
OAuth 2.0 không quy định token format cụ thể. Tuy nhiên, authorization server như Google, Facebook, GitHub mặc định trả opaque token. Bạn có thể cấu hình để nhận JWT thay vì opaque token.
JWT có bị giả mạo không?
Không nếu dùng đúng algorithm và bảo mật secret key. Dùng RS256 (asymmetric) thay vì HS256 (symmetric) để public key có thể share cho nhiều service mà private key vẫn bảo mật.
Tham khảo
Tài liệu chính thức: RFC 7519 – JWT, OAuth 2.0. Tìm hiểu thêm về token security tại Auth0 Token Documentation.
Kết luận
Opaque Token và JWT phục vụ những mục đích khác nhau: