提示:本网站现在为维护调试状态

JWT Security Best Practices + OAuth2 vs SAML

Choyeon
Choyeon
Sep 12, 2026 1 min read 274 Views
458 words 2,981 chars Updated Nov 8, 2026
JWT Security Best Practices + OAuth2 vs SAML
Table of contents

JWT is ubiquitous for stateless cross-service convenience but sloppy config is a top attack target. Modern systems also need third-party login or enterprise SSO so choosing the right federation protocol is mandatory architect knowledge.

JWT Secure Implementation Checklist

Never sign tokens client-side with symmetric HMAC secrets. Production uses RS256/ES256 asymmetric - public keys verify openly. Whitelist only allowed algorithms; compare iss/aud with timingSafeEqual to prevent timing oracles; track jti blacklists for revocation.

import { createSign, createVerify, randomBytes, timingSafeEqual } from "node:crypto";

export interface JwtConfig {
    algorithm: "RS256";
    privateKeyPem: string;
    publicKeyPem: string;
    issuer: string;
    audience: string;
    accessTokenTtlSec: number;
    allowedAlgos: readonly string[];
}
export interface TokenPayload {
    sub: string; scopes: readonly string[]; jti: string;
    exp: number; nbf: number; iat: number; iss: string; aud: string;
}
const B64 = {
    enc: (b: Buffer) => b.toString("base64url"),
    dec: (s: string) => Buffer.from(s, "base64url"),
};
const DENIED = new Set<string>();

export function createJwt(cfg: JwtConfig, claims: Partial<TokenPayload> & { sub: string; scopes: readonly string[] }): string {
    const now = Math.floor(Date.now() / 1000);
    const header = { alg: cfg.algorithm, typ: "JWT", kid: "k1" };
    const payload: TokenPayload = {
        sub: claims.sub, scopes: claims.scopes,
        jti: randomBytes(16).toString("hex"),
        iat: now, nbf: now, exp: now + cfg.accessTokenTtlSec,
        iss: cfg.issuer, aud: cfg.audience,
    };
    const input = `${B64.enc(Buffer.from(JSON.stringify(header)))}.${B64.enc(Buffer.from(JSON.stringify(payload)))}`;
    const s = createSign("RSA-SHA256"); s.update(input);
    return `${input}.${B64.enc(s.sign(cfg.privateKeyPem))}`;
}

export function verifyJwt(cfg: JwtConfig, token: string): TokenPayload {
    const parts = token.split(".");
    if (parts.length !== 3) throw new Error("malformed");
    const [hB64, pB64, sB64] = parts;
    const header = JSON.parse(B64.dec(hB64).toString());
    if (!cfg.allowedAlgos.includes(header.alg) || header.alg === "none") throw new Error("alg not allowed");
    const ver = createVerify("RSA-SHA256"); ver.update(`${hB64}.${pB64}`);
    if (!ver.verify(cfg.publicKeyPem, B64.dec(sB64))) throw new Error("signature mismatch");
    const p = JSON.parse(B64.dec(pB64).toString()) as TokenPayload;
    if (!timingSafeEqual(Buffer.from(p.iss), Buffer.from(cfg.issuer))) throw new Error("iss");
    if (p.aud !== cfg.audience) throw new Error("aud");
    const now = Math.floor(Date.now() / 1000);
    if (p.exp < now) throw new Error("expired");
    if (p.nbf > now) throw new Error("not yet valid");
    if (DENIED.has(p.jti)) throw new Error("revoked");
    return p;
}

OAuth2 / OIDC / SAML Compared

OAuth2 is an authorization framework, NOT authentication. OpenID Connect adds id_token on top of OAuth2 to deliver real login. SAML 2.0 is classic enterprise federation with XML payloads - compatible but clunky on mobile.

Feature OAuth2 + PKCE OIDC (over OAuth2) SAML 2.0
Nature Delegated authorization User authentication Federated authN+authZ
Best fit Mobile / SPA Web/Mobile/APIs Enterprise internal SSO
Credentials access_token only access_token + id_token (JWT) SAML Assertion (XML)
Security Requires PKCE against CSRF Native nonce support Signed XML, complex flows
Mobile UX Great (app transitions) Great Poor (many redirects)
Integration complexity Medium Low High (metadata exchange)

Best Practices

If JWTs carry sensitive scope: short TTL (5-15 min) + refresh token rotation. SPAs should store refresh tokens in HttpOnly cookies to sidestep XSS. Standardize on OIDC for any third-party login scenario.

X微博Telegram

About the author

Poll

你最希望 Rosetta 优先加入哪项功能?

社区投票(演示数据,可后台删除)

Comments (4)

0 / 3000
画画的小鱼
画画的小鱼fishgallery.artSep 21, 2026

有个小问题:你文中用的是 @Async 注解,这个默认用的是 SimpleAsyncTaskExecutor,生产环境是不是最好手动配一个线程池?

考研加油鸭
考研加油鸭kaoyan-journey.xyzSep 21, 2026

作为一个刚入行的后端新人,这篇文章帮我理清了好多概念,谢谢博主持续输出高质量内容!

代码幽灵
代码幽灵ghostdev.blogSep 20, 2026

哈哈,楼主的踩坑经历和我一模一样!我当时就是没注意到这个配置,排查了整整两天,看到这篇文章泪目了。

游戏策划阿哲
游戏策划阿哲Sep 20, 2026

写得太好了,终于搞懂了分布式事务的几种方案区别,收藏了!

Related posts

GraphQL vs REST: 7-Dimension Deep Comparison

GraphQL vs REST: 7-Dimension Deep Comparison

End the API style debate: compared across 7 dimensions - network efficiency, DX, evolution cost, caching, type-safety, security risks, ecosystem - with clear decision tree and hybrid architecture patterns.

1 min read
Prompt Engineering 101: Few-Shot + CoT + Structured Output

Prompt Engineering 101: Few-Shot + CoT + Structured Output

Systematic prompt engineering primer covering three core techniques: Few-Shot examples for style injection, Chain-of-Thought for complex reasoning, JSON Schema enforced structured outputs for downstream systems. Includes real templates and anti-patterns.

1 min read
CQRS + Event Sourcing Architecture Patterns

CQRS + Event Sourcing Architecture Patterns

Advanced patterns: CQRS separate read/write models for query performance; Event Sourcing using events as source of truth for audit + time travel. Covers consistency, snapshots, idempotency pitfalls and anti-patterns.

1 min read
Test Pyramid: Unit/Integration/E2E Ratios & Implementation

Test Pyramid: Unit/Integration/E2E Ratios & Implementation

Systematic test pyramid breakdown: bottom unit tests (many, fast, mock isolated), middle integration tests (real service/db/message interaction), top E2E tests (few, critical user flows). Recommended ratio 70/20/10, with coverage metrics and implementation playbook.

1 min read
Quick Start with FastAPI - Building High-Performance REST APIs

Quick Start with FastAPI - Building High-Performance REST APIs

FastAPI stands out among modern Python web frameworks with auto-generated docs based on type hints, async support, and Node.js-level performance. This hands-on guide builds a complete CRUD API from scratch covering route definition, request validation, dependency injection, and database integration—master FastAPI essentials in 30 minutes.

This post requires a password 4 min read
Alembic Deep Dive: Migrations, Autogenerate, and Branch Merging

Alembic Deep Dive: Migrations, Autogenerate, and Branch Merging

Comprehensive Alembic (official SQLAlchemy migration tool) guide: env.py setup, autogenerate detecting model changes (fields, indexes, constraints), batch scripts, downgrade rollback strategies, plus standard SOP for multi-developer migration branch conflicts and divergent head merging, with production deploy checklist.

1 min read