system design

Access Token Service Low-Level Design: JWT Signing, Key Rotation, and Claim Customization

What Is an Access Token Service?

An access token service issues short-lived cryptographically signed tokens that authorize access to protected resources. JWTs (JSON Web Tokens) are the dominant format: self-contained, verifiable without a database lookup, and extensible via custom claims. The critical design concerns are algorithm selection for signing, JWKS endpoint exposure for public key distribution, safe key rotation without service interruption, and a flexible claim customization pipeline.

Requirements

Functional Requirements

  • Issue signed JWTs with a configurable expiry (default 15 minutes) for authenticated principals.
  • Support RS256 (RSA + SHA-256) and ES256 (ECDSA + P-256) signing algorithms.
  • Expose a JWKS (JSON Web Key Set) endpoint so resource servers can verify tokens without calling the auth service on every request.
  • Rotate signing keys on a schedule (default 30 days) without invalidating tokens issued under the previous key.
  • Allow per-client claim customization: inject tenant_id, roles, scopes, and arbitrary metadata.

Non-Functional Requirements

  • Token issuance latency under 10 ms at p99.
  • JWKS endpoint must be cacheable and available independently of the issuance path.
  • Private keys must never appear in logs, error messages, or API responses.

Data Model

Signing Key Record

  • kid — Key ID, UUID; included in JWT header so verifiers know which key to use.
  • algorithm — RS256 or ES256.
  • private_key_ref — reference to encrypted private key in a secrets manager (Vault, AWS KMS); never stored in plaintext in the database.
  • public_key_jwk — serialized public key in JWK format; safe to store and serve.
  • status — ENUM: ACTIVE, RETIRING, RETIRED.
  • created_at, retire_at, delete_at.

Token Issuance Log (optional, for audit)

  • jti — JWT ID, unique per token; enables revocation lookup.
  • sub, client_id, issued_at, expires_at, kid.

Core Algorithm: Token Issuance

Step 1 — Principal Verification

Receive an authenticated request (valid session cookie, client credentials, or authorization code). Extract the principal identity and client context.

Step 2 — Claim Assembly

Build the standard claims: iss (issuer URL), sub (subject), aud (audience), iat, exp, jti. Invoke the claim customization pipeline: load per-client claim rules from a configuration store, evaluate each rule against the principal context, and merge custom claims (roles, scopes, tenant_id, feature flags) into the payload. Validate that no reserved claims are overwritten by custom rules.

Step 3 — Signing

Retrieve the current ACTIVE signing key. Fetch the private key from the secrets manager (cache the decrypted key object in-process for the key lifetime to avoid per-token KMS calls). Sign the JWT using the selected algorithm. Include kid in the JOSE header. Return the compact serialization.

Key Rotation Algorithm

Key rotation must not interrupt verification: resource servers cache the JWKS with a short TTL (5 minutes) and must be able to verify tokens issued under both the old and new key during the overlap period.

  • T-7 days: Generate new key pair. Set status to ACTIVE. Add to JWKS. Old key moves to RETIRING (still in JWKS, still valid for verification).
  • T+0 (rotation day): New key becomes the default signing key. All new tokens use the new kid.
  • T+max_token_lifetime: Old key moves to RETIRED. Remove from JWKS. Tokens signed with it are now expired anyway.
  • delete_at: Remove private key from secrets manager. Retain public key record for audit.

JWKS Endpoint Design

Serve GET /.well-known/jwks.json as a static JSON document containing all ACTIVE and RETIRING public keys. Set Cache-Control: max-age=300, stale-while-revalidate=60. Resource servers should implement a key refresh on encountering an unknown kid rather than hard-failing, enabling zero-downtime rotation. The JWKS document should be served from a CDN or edge cache to handle high verification traffic without hitting the auth service.

API Design

  • POST /token — issue an access token; accepts grant_type, client credentials or authorization code.
  • GET /.well-known/jwks.json — public key set for token verification.
  • GET /.well-known/openid-configuration — discovery document pointing to JWKS and token endpoints.
  • POST /token/introspect — active/inactive check for opaque token compatibility (optional).
  • POST /admin/keys/rotate — trigger manual key rotation (admin-only, protected by mTLS).

Scalability Considerations

Token issuance is CPU-bound (RSA signing is more expensive than ECDSA; prefer ES256 for high-throughput scenarios). Cache the loaded private key object in-process to eliminate KMS round-trips. Run multiple stateless issuance instances behind a load balancer; all share the same signing key fetched from a central secrets manager. The JWKS endpoint is read-only and cacheable; serve it from a CDN with 5-minute TTL and origin shield to handle millions of verifications per second without load on the auth service.

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering

See also: Stripe Interview Guide 2026: Process, Bug Bash Round, and Payment Systems

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

1972 Soviet postage stamp commemorating the Mars 2 probe

worth a read

Mars For The Rest of Us — a weekly-or-more deep dive on the technical side of Mars exploration: rocket propulsion, microbiology, mission architecture, and everything in between. Written by Maciej Ceglowski.

Read it on Substack →
Scroll to Top