Files
spring-auth-demo/refresh-tokens/README.md
T

2.1 KiB

refresh-tokens

Companion code for JWT Refresh Token Rotation in Spring Security 7 (With Reuse Detection).

Short-lived access JWT, opaque rotating refresh token, token families, reuse detection, logout on one device and everywhere. H2 in memory, no external services.

Run it: mvn test (JDK 25, Spring Boot 4.1.2, Spring Security 7.1.2). Every test writes what it observed to output/, and scripts/run-all.sh regenerates all of it, including a real HTTP walkthrough.

file what it shows
01-rotation.txt login, two rotations, one family; the access token carries the family id as sid
02-storage.txt the table holds the SHA-256 of the token, never the token
03-reuse-detection.txt a replayed token revokes the family, including the innocent holder's newest token
04-families-are-independent.txt a replay on the phone does not touch the laptop's login
05-concurrent-refresh-strict.txt 8 simultaneous requests with one token: 1 wins, the family is then revoked
06-concurrent-refresh-grace.txt the same stampede with reuse-grace=5s: the family survives, the late replay still kills it
07-logout.txt single-device logout, logout everywhere, and the access token that outlives both
08-check-sid.txt demo.check-sid=true makes the access token die with its family
09-expiry.txt idle timeout versus the absolute family cap
10-clock-skew.txt Spring Security's default validator accepts a token 30 seconds past exp
11-identical-refusals.txt unknown, reused, revoked and expired answer with the same bytes
12-http-walkthrough.txt the same story over real HTTP with curl

Settings in application.yaml: demo.jwt.access-ttl (5m), demo.refresh.token-ttl (7d), demo.refresh.family-max-age (30d), demo.refresh.reuse-grace (0s), demo.check-sid (false).

Token fingerprints and family ids differ on every run because the tokens are random. Statuses, counts and HTTP codes do not. The signing secret in application.yaml is a demo value. Read yours from a secret manager.