Batch 8 issued plain UUIDs as session tokens. Batch 12 replaces them with HMAC-SHA256-signed tokens carrying an explicit exp timestamp, per-process signing key, and a revocation map so logout actually invalidates. Disabled users (status != "enabled") are rejected even with a valid signature.
Batch 8 ออก token แบบ UUID · Batch 12 เปลี่ยนเป็น token ที่ลงนาม HMAC พร้อม exp ชัดเจน · มี key ต่อ process · มี map สำหรับ revoke ตอน logout · ถ้า status ไม่ใช่ enabled จะ reject แม้ลายเซ็นยังใช้ได้
Signed sessions · explicit expiry · revocation on logout · disabled-user lockout. Still no password — out of scope this batch.
Token ลงนาม · หมดอายุชัด · logout ใช้งานได้จริง · disabled user ล็อก · ยังไม่มี password
Token format: <base64url(payload)>.<base64url(hmac_sha256)>. Payload: {"sub": profile_id, "iat": int, "exp": int, "v": "das-1"}. Signing key defaults to a per-process random secret (secrets.token_hex(32)), overridable via DAS_SIGNING_KEY. TTL defaults to 24h, overridable via DAS_SESSION_TTL. The Batch-8 session map is preserved as a revocation set: tokens not in the map are treated as invalid even if signed correctly (so logout works and the per-process key rotation on restart invalidates all old sessions).
| Aspect | Batch 8 | Batch 12 |
|---|---|---|
| Token | plain UUID v4 | HMAC-SHA256 signed · body.sig |
| Expiry | none (cookie max-age only) | explicit exp claim · checked on every verify |
| Tamper detection | none | constant-time HMAC compare |
| Disabled users | allowed if they had a token | rejected on every verify |
| Restart behavior | tokens survived (UUID stayed valid) | per-process random key → restart invalidates all tokens |
| Logout | UUID removed from map | signature removed from revocation map |
body = base64url(JSON.stringify({
sub: "u-admin-001",
iat: 1745083200, // unix seconds
exp: 1745169600, // unix seconds · iat + 86400
v: "das-1"
}))
sig = base64url(HMAC-SHA256(signing_key, body))
token = body + "." + sigThe verifier MUST: (1) split on ., (2) recompute HMAC on the raw body bytes, (3) compare with hmac.compare_digest, (4) decode payload, (5) check exp > now, (6) ensure the signature is still in the revocation set.
| Var | Default | Purpose |
|---|---|---|
DAS_SIGNING_KEY | per-process random | Share across restarts in dev by setting explicitly. In production replace with a secret manager value. |
DAS_SESSION_TTL | 86400 | Session lifetime in seconds. |
* for dev.