Bài viết này liên quan đến API là gì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 TokenJWT phục vụ những mục đích khác nhau:

Chào các bạn mình là Quốc Hùng , mình sinh ra thuộc cung song tử ,song tử luôn khẳng định chính mình ,luôn luôn phấn đấu vượt lên phía trước ,mình sinh ra và lớn lên tại vùng đất võ cổ truyền ,đam mê của mình là coder ,ngày đi học tối về viết blog ...