Intermediate · Secure

Choose Sessions, JWTs, and Refresh Tokens by Threat Model

Compare server-side sessions with self-contained bearer access tokens and design refresh rotation.

Primary source: Spring Security 6.5 Reference Architecture

50 min

Lesson 2 of 5

1d streak

The Architectural Question

Token lifetime, storage, and revocation decisions set the blast radius of a breach; defaults chosen casually become the postmortem.

What this guide proves

  • Hash passwords with an adaptive one-way function
  • Keep access tokens short lived and validate all required claims
  • Treat refresh tokens as high-value credentials with replay detection

Stateful Sessions vs Stateless JWTs: Architectural Threat Modeling

Choosing between server-side HTTP sessions and client-side JSON Web Tokens (JWT) is not a matter of style; it is an architectural decision based on threat models, state storage, and revocation requirements.

Architectural Boundary · Do Not Confuse

Concept A

Stateful HTTP Sessions: Server stores session ID in memory or Redis; client holds cookie (JSESSIONID). A server-side session can be revoked immediately on logout. HttpOnly reduces token theft through JavaScript, but XSS can still act through the browser; cookie flows also need CSRF protection. Requires server-side session clustering.

Concept B

Stateless JWT Bearer Tokens: Cryptographically signed token held by client. Microservices validate signature offline using public keys without hitting a database. Signature validation alone does not provide revocation before expiration; use short expirations, key rotation, introspection, or an explicit revocation check when the threat model requires it.

Use sessions for monolithic web apps or server-rendered frontends. Use stateless JWTs for distributed microservice resource servers where hitting a shared session database on every request introduces latency bottlenecks.

The Storage Rule for JWTs in Single Page Applications

Never store JWT access tokens in browser localStorage or sessionStorage. Any Cross-Site Scripting (XSS) vulnerability in any third-party npm package can steal the token immediately. Store tokens in memory or use HttpOnly; SameSite=Strict cookies.

Active Recall Checkpoint

Why is revoking an individual JWT token immediately upon user logout challenging in a pure stateless architecture?

Hint: Does the resource server query a central database when verifying the JWT signature?

Show answer & explanation

Because resource servers validate the cryptographic signature locally without calling an identity provider. Until the token reaches its exp (expiration) timestamp, the signature remains valid regardless of user actions.

JWT Cryptography: HMAC (HS256) vs Asymmetric (RS256/ES256)

A JSON Web Token consists of three base64url-encoded parts separated by periods: Header.Payload.Signature. The signature guarantees that the payload has not been tampered with in transit.

Algorithm TypeSigning KeyVerification KeySecurity Fit
Symmetric (HS256)Shared Secret (256-bit string)Same Shared SecretInternal single-app services. If a resource server is compromised, the attacker can forge valid tokens for any user.
Asymmetric (RS256 / ES256)Private Key (held strictly by Auth Server)Public Key (published via JWKS endpoint)Enterprise fit for independently operated resource servers. Resource servers verify tokens with public keys, so compromising a verifier does not reveal the signing private key; stolen valid tokens can still be misused until they expire or are revoked.
decoded-jwt.json
{
  "sub": "usr_948194",
  "iss": "https://auth.example.com",
  "aud": "https://api.example.com",
  "roles": ["ROLE_USER", "ROLE_ADMIN"],
  "exp": 1725710400,
  "nbf": 1725706800,
  "iat": 1725706800
}

Active Recall Checkpoint

What critical claims must a resource server validate before trusting a JWT?

Hint: Think about issuer, audience, and expiration.

Show answer & explanation

iss (issuer must match trusted authorization server), aud (audience must match this specific API), and exp (current time must be strictly before expiration timestamp).

Refresh Token Rotation & Mitigating Token Theft

To balance security with user convenience, production systems pair short-lived Access Tokens (5 to 15 minutes) with Refresh Token Rotation (RTR).

  1. 011. Client logs in: Auth server returns Access Token (15 min) and single-use Refresh Token (7 days)
  2. 022. Access Token expires: Client sends Refresh Token to /oauth/token
  3. 033. Auth Server validates Refresh Token, invalidates it immediately, and issues a NEW Access Token and NEW Refresh Token
  4. 044. Token Reuse Detection: If an attacker and legitimate user attempt to use the same Refresh Token twice, the Auth Server detects breach and invalidates all active tokens in that family immediately.

The Reuse Detection Guarantee

Reuse detection can limit the impact of a stolen refresh token, but the result depends on the identity provider, atomic token-family storage, race handling, and its revocation policy.

Active Recall Checkpoint

What happens when an identity provider detects that a previously exchanged refresh token is presented a second time?

Hint: What does this indicate about possible token interception?

Show answer & explanation

It indicates token theft. The identity provider revokes the entire token family (the refresh token and all associated access tokens), forcing the legitimate user to re-authenticate.

Deliberate Failure Lab: The Stateless Revocation Gap

Consider an employee fired at 2:00 PM. The administrator disables their account in the database. If the employee possesses an access token issued with a 12-hour expiration, they can continue querying protected APIs until 2:00 AM if this resource server only validates the signature and does not perform introspection or a revocation check.

Architectural Defenses Against the Revocation Gap

1. Keep access token lifespans strictly under 10–15 minutes. 2. For critical operations (password change, money transfer), enforce step-up authentication or check a lightweight Redis distributed blocklist of revoked jti (JWT ID) claims.

Active Recall Checkpoint

How does a five-minute access-token lifetime change the revocation window, and what risk remains?

Hint: What is the maximum window of vulnerability after an account is suspended?

Show answer & explanation

The token may remain usable until its expiry in this configured design. A shorter lifetime reduces that window, but it does not revoke an already-issued token immediately; introspection or a revocation check is needed when immediate suspension matters.

Runtime Architecture & Flow

Decision canvas

Evaluate the choice across three constraints

These are comparison criteria, not sequential steps. A strong answer states which constraint dominates in the current system.

CRITERION 01

Hash passwords with an adaptive one-way function

Ask how each option changes this guarantee, its operational cost, and its failure mode.

CRITERION 02

Keep access tokens short lived and validate all required claims

Ask how each option changes this guarantee, its operational cost, and its failure mode.

CRITERION 03

Treat refresh tokens as high-value credentials with replay detection

Ask how each option changes this guarantee, its operational cost, and its failure mode.

Decision prompt: Implement login and rotate a refresh token after every successful use.

Working Implementation

Code Walkthrough

Implement login and rotate a refresh token after every successful use.

JwtTokenRotationLab.java
package com.example.security;

import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class JwtTokenRotationLab {
    public record TokenPair(String accessToken, String refreshToken, Instant expiresAt) {}

    // In-memory token family storage for rotation tracking
    private final Map<String, String> activeRefreshTokens = new ConcurrentHashMap<>();

    public TokenPair issueInitialTokens(String userId) {
        String accessToken = "jwt_access_" + UUID.randomUUID() + "_" + userId;
        String refreshToken = "rfr_" + UUID.randomUUID();
        activeRefreshTokens.put(refreshToken, userId);
        return new TokenPair(accessToken, refreshToken, Instant.now().plus(Duration.ofMinutes(15)));
    }

    public TokenPair rotateRefreshToken(String presentedRefreshToken) {
        String userId = activeRefreshTokens.remove(presentedRefreshToken);
        if (userId == null) {
            // Replay detected! Invalidate entire user session family
            throw new SecurityException("Refresh token reuse detected! Revoking token family.");
        }
        String newAccessToken = "jwt_access_" + UUID.randomUUID() + "_" + userId;
        String newRefreshToken = "rfr_" + UUID.randomUUID();
        activeRefreshTokens.put(newRefreshToken, userId);
        return new TokenPair(newAccessToken, newRefreshToken, Instant.now().plus(Duration.ofMinutes(15)));
    }
}
Stateless JWT access tokens carry a short lifespan (15 minutes) to minimize the revocation gap.
Refresh Token Rotation (RTR) issues a single-use refresh token that invalidates upon first presentation.
If an already-used refresh token is presented again, reuse detection revokes all tokens in that family.

Synthesis & Production Verification

Production Acceptance Criteria

  • Store passwords hashed with BCrypt or Argon2 and verify encoder strength
  • Expire access tokens in minutes and validate iss, aud, and exp claims
  • Rotate refresh tokens per use and reject replayed ones

Architectural & Technical Review

Core Interview Questions

Q01When should an architecture choose stateful sessions over stateless JWTs?Show answer

Stateful sessions are ideal for monolithic web applications with server-side rendering or high-security banking where immediate server-side revocation on logout is mandatory.

Q02What is the cryptographic advantage of asymmetric (RS256) JWTs over symmetric (HS256)?Show answer

Asymmetric signing allows the authorization server to hold the private signing key while distributing the public key via JWKS. Resource servers verify signatures without the ability to forge new tokens.

Q03How does Refresh Token Rotation (RTR) mitigate stolen refresh token vulnerabilities?Show answer

Each refresh token can only be exchanged once; exchanging it issues a new access/refresh token pair and invalidates the previous token. If an invalidated token is reused, the entire token family is revoked.

Production Pitfalls

Critical Anti-Patterns

  • Pitfall: Storing JWT access tokens in browser localStorage vulnerable to XSS — Any XSS vulnerability in client scripts can extract localStorage tokens; store tokens in memory or HttpOnly cookies.
  • Pitfall: Using long-lived JWT access tokens without refresh rotation or revocation mechanisms — Stateless access tokens cannot be revoked before expiration; keep lifetimes strictly under 10–15 minutes.

Primary Documentation & Specifications

Supplementary Module Resources