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 be seamless: 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.

Summary

An access token service combines secure key management, flexible claim assembly, and cacheable public key distribution. RS256 provides broad compatibility; ES256 offers faster signing for high throughput. Overlap-based key rotation ensures zero-downtime transitions, and a CDN-backed JWKS endpoint decouples token verification scale from issuance capacity.

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

Scroll to Top