Bộ mã hóa JWT
Tạo và ký JSON Web Tokens với HS256, HS384, HS512
Tiêu đề
Dữ liệu
Khóa bí mật
JWT được mã hóa
Khóa bí mật của bạn không bao giờ rời khỏi trình duyệt. Tất cả chữ ký được thực hiện phía máy khách.
JWT Encoding là gì?
JWT encoding là quá trình tạo JSON Web Token — một chuỗi nhỏ gọn và an toàn URL chứa một tập hợp các yêu cầu được ký bằng khóa mật mã. Kết quả là một token ba phần (header.payload.signature) được định nghĩa bởi RFC 7519 mà các máy chủ có thể xác minh mà không cần duy trì trạng thái phiên.
Header khai báo thuật toán ký (ví dụ HS256) và loại token. Payload chứa các claim — các cặp key-value như chủ thể (sub), thời gian hết hạn (exp) và bất kỳ dữ liệu tùy chỉnh nào ứng dụng của bạn cần. Cả hai phần đều được tuần tự hóa dưới dạng JSON, sau đó được mã hóa base64url. Signature được tính toán trên header và payload đã mã hóa bằng khóa bí mật, liên kết cả ba phần lại với nhau.
Không giống cookie phiên, JWT có tính tự chứa: bên xác minh không cần truy vấn cơ sở dữ liệu hay gọi dịch vụ bên ngoài. Điều này làm cho xác thực dựa trên JWT trở nên phổ biến trong REST API, microservice và ứng dụng trang đơn, nơi phân quyền không trạng thái giảm độ trễ và đơn giản hóa mở rộng theo chiều ngang.
Tại sao dùng JWT Encoder?
Tạo JWT thủ công đòi hỏi mã hóa base64url, tuần tự hóa JSON và tính toán HMAC. Công cụ này xử lý cả ba bước ngay lập tức để bạn có thể tập trung vào việc thiết lập đúng các claim.
Trường hợp sử dụng JWT Encoder
HS256 vs HS384 vs HS512: So sánh thuật toán HMAC
Cả ba thuật toán đều dùng HMAC (Hash-based Message Authentication Code) với bí mật chung. Sự khác biệt là hàm băm bên dưới, ảnh hưởng đến độ dài signature và mức độ bảo mật. Đối với hầu hết ứng dụng, HS256 cung cấp đủ bảo mật. Chọn HS384 hoặc HS512 khi yêu cầu tuân thủ (ví dụ FIPS-140) bắt buộc dùng hàm băm mạnh hơn hoặc khi token của bạn mang các quyết định phân quyền có giá trị cao.
| Thuật toán | Hàm băm | Signature | Tốc độ | Sử dụng điển hình |
|---|---|---|---|---|
| HS256 | SHA-256 | 32 B | Fastest | General purpose, default for most libraries |
| HS384 | SHA-384 | 48 B | Fast | Higher security margin, FIPS-140 compliant |
| HS512 | SHA-512 | 64 B | Fast | Maximum HMAC security, large payloads |
Tham chiếu các Claim JWT chuẩn
RFC 7519 định nghĩa bảy claim đã đăng ký. Không có claim nào bắt buộc, nhưng sử dụng đúng chúng sẽ cải thiện khả năng tương tác và bảo mật. Claim exp đặc biệt quan trọng — token không có thời hạn hết hạn sẽ có hiệu lực vô thời hạn nếu bí mật không được thay đổi.
| Claim | Tên | Mô tả | Ví dụ |
|---|---|---|---|
| iss | Issuer | Who issued the token | "auth.example.com" |
| sub | Subject | Who the token represents | "user-123" |
| aud | Audience | Intended recipient service | "api.example.com" |
| exp | Expiration | Unix timestamp — token invalid after this time | 1717203600 |
| nbf | Not Before | Unix timestamp — token invalid before this time | 1717200000 |
| iat | Issued At | Unix timestamp when the token was created | 1717200000 |
| jti | JWT ID | Unique token identifier for revocation tracking | "a1b2c3d4" |
JWT Encoding trong Code
Các ví dụ này cho thấy cách tạo và ký JWT theo chương trình. Mỗi đoạn code tạo ra token HS256 hợp lệ. Đối với hệ thống sản xuất, luôn đặt claim exp và dùng bí mật ngẫu nhiên mật mã có ít nhất 256 bit.
async function signJWT(payload, secret, alg = 'HS256') {
const header = { alg, typ: 'JWT' }
const enc = new TextEncoder()
// Base64url encode header and payload
const b64url = (obj) =>
btoa(JSON.stringify(obj)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const h = b64url(header)
const p = b64url(payload)
// Sign with HMAC-SHA256
const key = await crypto.subtle.importKey(
'raw', enc.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
)
const sig = await crypto.subtle.sign('HMAC', key, enc.encode(`${h}.${p}`))
const s = btoa(String.fromCharCode(...new Uint8Array(sig)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
return `${h}.${p}.${s}`
}
// Usage
const token = await signJWT(
{ sub: 'user-123', name: 'Alice', iat: Math.floor(Date.now() / 1000) },
'your-256-bit-secret'
)
// → "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOi..."import jwt
import time
payload = {
"sub": "user-123",
"name": "Alice",
"iat": int(time.time()),
"exp": int(time.time()) + 3600, # expires in 1 hour
}
# Sign with HS256 (default)
token = jwt.encode(payload, "your-256-bit-secret", algorithm="HS256")
# → "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOi..."
# Verify and decode
decoded = jwt.decode(token, "your-256-bit-secret", algorithms=["HS256"])
# → {"sub": "user-123", "name": "Alice", "iat": 1717200000, "exp": 1717203600}const jwt = require('jsonwebtoken')
const payload = {
sub: 'user-123',
name: 'Alice',
role: 'admin',
}
// Sign — iat is added automatically
const token = jwt.sign(payload, 'your-256-bit-secret', {
algorithm: 'HS256',
expiresIn: '1h', // sets exp claim
issuer: 'auth.example.com', // sets iss claim
})
// Verify
const decoded = jwt.verify(token, 'your-256-bit-secret')
// → { sub: 'user-123', name: 'Alice', role: 'admin', iat: ..., exp: ... }package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
func main() {
claims := jwt.MapClaims{
"sub": "user-123",
"name": "Alice",
"iat": time.Now().Unix(),
"exp": time.Now().Add(time.Hour).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signed, _ := token.SignedString([]byte("your-256-bit-secret"))
fmt.Println(signed)
// → eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOi...
}