Auth Patterns — Authentication & Authorization
SECURITY-CRITICAL SKILL — Auth is the front door. Get it wrong and nothing else matters.
Authentication Methods
| Method | How It Works | Best For |
|---|
| JWT | Signed token sent with each request | SPAs, microservices, mobile APIs |
| Session-based |
Server stores session, client holds cookie | Traditional web apps, SSR |
|
OAuth 2.0 | Delegated auth via authorization server | "Login with Google/GitHub", API access |
|
API Keys | Static key sent in header | Internal services, public APIs |
|
Magic Links | One-time login link via email | Low-friction onboarding, B2C |
|
Passkeys/WebAuthn | Hardware/biometric challenge-response | High-security apps, passwordless |
JWT Patterns
Dual-Token Strategy
Short-lived access token + long-lived refresh token:
CODEBLOCK0
Token Structure
CODEBLOCK1
Signing Algorithms
| Algorithm | Type | When to Use |
|---|
| RS256 | Asymmetric (RSA) | Microservices — only auth server holds private key |
| ES256 |
Asymmetric (ECDSA) | Same as RS256, smaller keys and signatures |
|
HS256 | Symmetric | Single-server apps — all verifiers share secret |
Prefer RS256/ES256 in distributed systems.
Token Storage
| Storage | XSS Safe | CSRF Safe | Recommendation |
|---|
| httpOnly cookie | Yes | No (add CSRF token) | Best for web apps |
| localStorage |
No | Yes | Avoid — XSS exposes tokens |
|
In-memory | Yes | Yes | Good for SPAs, lost on refresh |
CODEBLOCK2
Expiration Strategy
| Token | Lifetime | Rotation |
|---|
| Access token | 5–15 minutes | Issued on refresh |
| Refresh token |
7–30 days | Rotate on every use |
|
ID token | Match access token | Not refreshed |
OAuth 2.0 Flows
| Flow | Client Type | When to Use |
|---|
| Authorization Code + PKCE | Public (SPA, mobile) | Default for all public clients |
| Authorization Code |
Confidential (server) | Server-rendered web apps with backend |
|
Client Credentials | Machine-to-machine | Service-to-service, cron jobs |
|
Device Code | Input-constrained | Smart TVs, IoT, CLI on headless servers |
Implicit flow is deprecated. Always use Authorization Code + PKCE for public clients.
PKCE Flow
CODEBLOCK3
Session Management
Server-Side Sessions
CODEBLOCK4
| Store | Speed | When to Use |
|---|
| Redis | Fast | Production default — TTL support, horizontal scaling |
| PostgreSQL |
Moderate | When Redis is overkill, need audit trail |
|
In-memory | Fastest | Development only |
Session Security
| Threat | Prevention |
|---|
| Session fixation | Regenerate session ID after login |
| Session hijacking |
httpOnly + Secure cookies, bind to IP/user-agent |
| CSRF | SameSite cookies + CSRF tokens |
| Idle timeout | Expire after 15–30 min inactivity |
| Absolute timeout | Force re-auth after 8–24 hours |
Authorization Patterns
| Pattern | Granularity | When to Use |
|---|
| RBAC | Coarse (admin, editor, viewer) | Most apps — simple role hierarchy |
| ABAC |
Fine (attributes: dept, time, location) | Enterprise — context-dependent access |
|
Permission-based | Medium (post:create, user:delete) | APIs — decouple permissions from roles |
|
Policy-based (OPA/Cedar) | Fine | Microservices — externalized, auditable rules |
|
ReBAC | Fine (owner, member, shared-with) | Social apps, Google Drive-style sharing |
RBAC Implementation
CODEBLOCK5
Password Security
| Algorithm | Recommended | Memory-Hard | Notes |
|---|
| Argon2id | First choice | Yes | Resists GPU/ASIC attacks |
| bcrypt |
Yes | No | Battle-tested, 72-byte limit |
|
scrypt | Yes | Yes | Good alternative |
|
PBKDF2 | Acceptable | No | NIST approved, weaker vs GPU |
|
SHA-256/MD5 |
Never | No | Not password hashing |
NIST 800-63B: Favor length (12+ chars) over complexity rules. Check against breached password lists. Don't force periodic rotation unless breach suspected.
Multi-Factor Authentication
| Factor | Security | Notes |
|---|
| TOTP (Authenticator app) | High | Offline-capable, Google Authenticator / Authy |
| WebAuthn/Passkeys |
Highest | Phishing-resistant, hardware-backed |
|
SMS OTP | Medium | Vulnerable to SIM swap — avoid for high-security |
|
Hardware keys (FIDO2) | Highest | YubiKey — best for admin accounts |
|
Backup codes | Low (fallback) | One-time use, generate 10, store hashed |
Security Headers
| Header | Value |
|---|
| Strict-Transport-Security | INLINECODE0 |
| Content-Security-Policy |
Restrict script sources, no inline scripts |
|
X-Content-Type-Options |
nosniff |
|
X-Frame-Options |
DENY |
|
Referrer-Policy |
strict-origin-when-cross-origin |
|
CORS | Whitelist specific origins, never
* with credentials |
Common Vulnerabilities
| # | Vulnerability | Prevention |
|---|
| 1 | Broken authentication | MFA, strong password policy, breach detection |
| 2 |
Session fixation | Regenerate session ID on login |
| 3 | JWT
alg:none attack | Reject
none, validate
alg against allowlist |
| 4 | JWT secret brute force | Use RS256/ES256, strong secrets (256+ bits) |
| 5 | CSRF | SameSite cookies, CSRF tokens |
| 6 | Credential stuffing | Rate limiting, breached password check, MFA |
| 7 | Insecure password storage | Argon2id/bcrypt, never encrypt (hash instead) |
| 8 | Insecure password reset | Signed time-limited tokens, invalidate after use |
| 9 | Open redirect | Validate redirect URIs against allowlist |
| 10 | Token leakage in URL | Send tokens in headers or httpOnly cookies only |
| 11 | Privilege escalation | Server-side role checks on every request |
| 12 | OAuth redirect_uri mismatch | Exact match redirect URI validation, no wildcards |
| 13 | Timing attacks | Constant-time comparison for secrets |
NEVER Do
| # | Rule | Why |
|---|
| 1 | NEVER store passwords in plaintext or reversible encryption | One breach exposes every user |
| 2 |
NEVER put tokens in URLs or query parameters | Logged by servers, proxies, referrer headers |
| 3 |
NEVER use alg: none or allow algorithm switching in JWTs | Attacker forges tokens |
| 4 |
NEVER trust client-side role/permission claims | Users can modify any client-side value |
| 5 |
NEVER use MD5, SHA-1, or plain SHA-256 for password hashing | No salt, no work factor — cracked in seconds |
| 6 |
NEVER skip HTTPS in production | Tokens and credentials sent in cleartext |
| 7 |
NEVER log tokens, passwords, or secrets | Logs are broadly accessible and retained |
| 8 |
NEVER use long-lived tokens without rotation | A single leak grants indefinite access |
| 9 |
NEVER implement your own crypto | Use established libraries — jose, bcrypt, passport |
| 10 |
NEVER return different errors for "user not found" vs "wrong password" | Enables user enumeration |
认证模式 — 身份验证与授权
安全关键技能 — 认证是系统的门户。一旦出错,其他一切都无从谈起。
身份验证方法
| 方法 | 工作原理 | 最佳适用场景 |
|---|
| JWT | 每次请求携带签名令牌 | 单页应用、微服务、移动端API |
| 基于会话 |
服务端存储会话,客户端持有Cookie | 传统Web应用、服务端渲染 |
|
OAuth 2.0 | 通过授权服务器进行委托认证 | 使用Google/GitHub登录、API访问 |
|
API密钥 | 在请求头中发送静态密钥 | 内部服务、公开API |
|
魔法链接 | 通过邮件发送一次性登录链接 | 低门槛注册、B2C场景 |
|
通行密钥/WebAuthn | 硬件/生物特征挑战-响应 | 高安全应用、无密码方案 |
JWT模式
双令牌策略
短生命周期访问令牌 + 长生命周期刷新令牌:
客户端 → POST /auth/login → 服务端
客户端 ← { accesstoken, refreshtoken }
客户端 → GET /api/data (Authorization: Bearer ) → 服务端
客户端 ← 401 已过期
客户端 → POST /auth/refresh { refresh_token } → 服务端
客户端 ← { newaccesstoken, rotatedrefreshtoken }
令牌结构
json
{
header: { alg: RS256, typ: JWT, kid: key-2024-01 },
payload: {
sub: user_abc123,
iss: https://auth.example.com,
aud: https://api.example.com,
exp: 1700000900,
iat: 1700000000,
jti: unique-token-id,
roles: [user],
scope: read:profile write:profile
}
}
签名算法
| 算法 | 类型 | 使用场景 |
|---|
| RS256 | 非对称(RSA) | 微服务 — 仅认证服务持有私钥 |
| ES256 |
非对称(ECDSA) | 同RS256,密钥和签名更小 |
|
HS256 | 对称 | 单服务应用 — 所有验证者共享密钥 |
在分布式系统中优先使用RS256/ES256。
令牌存储
| 存储方式 | XSS安全 | CSRF安全 | 推荐建议 |
|---|
| httpOnly Cookie | 是 | 否(需添加CSRF令牌) | Web应用最佳选择 |
| localStorage |
否 | 是 | 避免使用 — XSS会暴露令牌 |
|
内存存储 | 是 | 是 | 适合SPA,刷新后丢失 |
Set-Cookie: access_token=eyJ...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=900
过期策略
| 令牌 | 生命周期 | 轮换机制 |
|---|
| 访问令牌 | 5–15分钟 | 刷新时重新签发 |
| 刷新令牌 |
7–30天 | 每次使用时轮换 |
|
ID令牌 | 与访问令牌一致 | 不进行刷新 |
OAuth 2.0流程
| 流程 | 客户端类型 | 使用场景 |
|---|
| 授权码 + PKCE | 公开客户端(SPA、移动端) | 所有公开客户端的默认方案 |
| 授权码 |
机密客户端(服务端) | 带后端服务渲染的Web应用 |
|
客户端凭证 | 机器对机器 | 服务间通信、定时任务 |
|
设备码 | 输入受限设备 | 智能电视、物联网、无头服务器CLI |
隐式流程已弃用。 公开客户端始终使用授权码 + PKCE。
PKCE流程
- 1. 客户端生成 codeverifier(随机43-128字符)
- 客户端计算 codechallenge = BASE64URL(SHA256(codeverifier))
- 重定向到 /authorize?codechallenge=...&codechallengemethod=S256
- 用户认证,服务端重定向返回授权码
- 客户端在 /token 端点交换 code + codeverifier 获取令牌
- 服务端验证 SHA256(codeverifier) == code_challenge
会话管理
服务端会话
客户端Cookie: session_id=a1b2c3d4(不透明、随机、不含用户数据)
服务端存储: { a1b2c3d4: { userId: 123, roles: [admin], expiresAt: ... } }
| 存储方式 | 速度 | 使用场景 |
|---|
| Redis | 快 | 生产环境默认 — 支持TTL、水平扩展 |
| PostgreSQL |
中等 | 当Redis过于复杂,需要审计追踪时 |
|
内存存储 | 最快 | 仅限开发环境 |
会话安全
| 威胁 | 预防措施 |
|---|
| 会话固定 | 登录后重新生成会话ID |
| 会话劫持 |
httpOnly + Secure Cookie,绑定IP/用户代理 |
| CSRF | SameSite Cookie + CSRF令牌 |
| 空闲超时 | 无活动15–30分钟后过期 |
| 绝对超时 | 8–24小时后强制重新认证 |
授权模式
| 模式 | 粒度 | 使用场景 |
|---|
| RBAC | 粗粒度(管理员、编辑者、查看者) | 大多数应用 — 简单角色层级 |
| ABAC |
细粒度(属性:部门、时间、位置) | 企业级 — 上下文相关访问控制 |
|
基于权限 | 中粒度(post:create、user:delete) | API — 将权限与角色解耦 |
|
基于策略(OPA/Cedar) | 细粒度 | 微服务 — 外部化、可审计规则 |
|
ReBAC | 细粒度(所有者、成员、共享对象) | 社交应用、Google Drive式共享 |
RBAC实现
typescript
const ROLE_PERMISSIONS: Record = {
admin: [user:read, user:write, user:delete, post:read, post:write, post:delete],
editor: [user:read, post:read, post:write],
viewer: [user:read, post:read],
};
function requirePermission(permission: string) {
return (req: Request, res: Response, next: NextFunction) => {
const permissions = ROLE_PERMISSIONS[req.user.role] ?? [];
if (!permissions.includes(permission)) {
return res.status(403).json({ error: Forbidden });
}
next();
};
}
app.delete(/api/users/:id, requirePermission(user:delete), deleteUser);
密码安全
| 算法 | 推荐等级 | 内存硬性 | 备注 |
|---|
| Argon2id | 首选 | 是 | 抵抗GPU/ASIC攻击 |
| bcrypt |
推荐 | 否 | 经过实战检验,72字节限制 |
|
scrypt | 推荐 | 是 | 良好替代方案 |
|
PBKDF2 | 可接受 | 否 | NIST批准,对GPU较弱 |
|
SHA-256/MD5 |
绝不使用 | 否 | 非密码哈希算法 |
NIST 800-63B: 优先考虑长度(12+字符)而非复杂度规则。对照已泄露密码库进行检查。除非怀疑被入侵,否则不强制定期轮换。
多因素认证
| 因素 | 安全性 | 备注 |
|---|
| TOTP(认证器应用) | 高 | 支持离线,Google Authenticator / Authy |
| WebAuthn/通行密钥 |
最高 | 抗钓鱼,硬件支持 |
|
短信OTP | 中等 | 易受SIM卡交换攻击 — 高安全场景避免使用 |
|
硬件密钥(FIDO2) | 最高 | YubiKey — 管理员账户最佳选择 |
|
备用码 | 低(备用方案) | 一次性使用,生成10个,存储哈希值 |
安全头
| 头字段 | 值 |
|---|
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload |
| Content-Security-Policy |
限制脚本来源,禁止