ตัวเข้ารหัส JWT
สร้างและลงนาม JSON Web Tokens ด้วย HS256, HS384, HS512
ส่วนหัว
เนื้อหา
คีย์ลับ
JWT ที่เข้ารหัส
คีย์ลับของคุณไม่ต้องออกจากเบราว์เซอร์ของคุณ การลงนามทั้งหมดเกิดขึ้นที่ฝั่งไคลเอนต์
JWT Encoding คืออะไร?
JWT encoding คือกระบวนการสร้าง JSON Web Token — สตริงที่กะทัดรัดและปลอดภัย URL ที่มีชุดของ claims ที่ลงนามด้วยคีย์การเข้ารหัส ผลลัพธ์คือ token สามส่วน (ส่วนหัว.ข้อมูล.ลายเซ็น) ที่กำหนดโดย RFC 7519 ที่เซิร์ฟเวอร์สามารถตรวจสอบได้โดยไม่ต้องรักษาสถานะเซสชั่น
header ประกาศอัลกอริทึมการลงนาม (เช่น HS256) และประเภทโทเค็น payload บรรจุ claims — คู่คีย์-ค่า เช่น subject (sub), เวลาหมดอายุ (exp) และข้อมูลที่กำหนดเองที่แอปพลิเคชันของคุณต้องการ ทั้งสองส่วนถูกแปลงเป็น JSON จากนั้น base64url-encoded ส่วน signature คำนวณจาก header และ payload ที่เข้ารหัสแล้วโดยใช้คีย์ลับ ผูกทั้งสามส่วนเข้าด้วยกัน
ต่างจาก session cookie JWT เป็นแบบพึ่งพาตัวเอง: ผู้ยืนยันไม่ต้องสอบถามฐานข้อมูลหรือเรียกบริการภายนอก ทำให้การตรวจสอบตัวตนด้วย JWT เป็นที่นิยมใน REST API ไมโครเซอร์วิส และ single-page application ที่การอนุญาตแบบไร้สถานะช่วยลด latency และทำให้การขยายแนวนอนง่ายขึ้น
ทำไมต้องใช้เครื่องมือเข้ารหัส JWT?
การสร้าง JWT ด้วยมือต้องใช้การ base64url encoding การแปลงเป็น JSON และการคำนวณ HMAC เครื่องมือนี้จัดการทั้งสามขั้นตอนทันที เพื่อให้คุณมุ่งเน้นไปที่การกำหนด claims ได้อย่างถูกต้อง
กรณีการใช้งานเครื่องมือเข้ารหัส JWT
HS256 vs HS384 vs HS512: การเปรียบเทียบอัลกอริทึม HMAC
ทั้งสามอัลกอริทึมใช้ HMAC (Hash-based Message Authentication Code) ร่วมกับคีย์ลับที่แชร์ ความแตกต่างอยู่ที่ฟังก์ชัน hash พื้นฐาน ซึ่งส่งผลต่อความยาว signature และระยะขอบความปลอดภัย สำหรับแอปพลิเคชันส่วนใหญ่ HS256 มีความปลอดภัยเพียงพอ เลือก HS384 หรือ HS512 เมื่อข้อกำหนดการปฏิบัติตามกฎเกณฑ์ (เช่น FIPS-140) กำหนดให้ใช้ hash ที่แข็งแกร่งขึ้น หรือเมื่อโทเค็นของคุณรองรับการตัดสินใจอนุญาตที่มีมูลค่าสูง
| อัลกอริทึม | Hash | Signature | ความเร็ว | การใช้งานทั่วไป |
|---|---|---|---|---|
| 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 |
การอ้างอิง Standard JWT Claims
RFC 7519 กำหนด registered claims เจ็ดรายการ ไม่มีรายการใดที่บังคับ แต่การใช้งานอย่างถูกต้องช่วยเพิ่ม interoperability และความปลอดภัย claim exp มีความสำคัญเป็นพิเศษ — โทเค็นที่ไม่มีวันหมดอายุจะใช้งานได้ไม่จำกัดหากไม่มีการหมุนเวียนคีย์ลับ
| Claim | ชื่อ | คำอธิบาย | ตัวอย่าง |
|---|---|---|---|
| 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 ในโค้ด
ตัวอย่างเหล่านี้แสดงวิธีสร้างและลงนาม JWT โดยใช้โปรแกรม แต่ละตัวอย่างสร้างโทเค็นที่ลงนาม HS256 ที่ถูกต้อง สำหรับระบบ production ควรตั้ง claim exp เสมอและใช้คีย์ลับที่สุ่มแบบ cryptographically secure อย่างน้อย 256 bits
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...
}