Ratgeber · JWT 2026
Refresh-Token-Pattern für JWT-basierte Auth
Access-Token 5-15 min, Refresh-Token 7-30 Tage, Rotation bei jedem Refresh, httpOnly-Cookie als Storage. Refresh-Token-Reuse-Detection.
Von Mateusz Viola
Betreiber & redaktionelle Verantwortung jwtdecoder.de
Veröffentlicht
Aktualisiert:
Das Problem mit langlebigen Access-Tokens
JWTs sind stateless - kein DB-Lookup pro Request. Vorteil: Skalierung. Nachteil: kein Revoke. Sobald ein Token ausgestellt ist, bleibt es bis exp gültig. Wenn der Token kompromittiert wird (XSS, Phishing, gestohlenes Gerät), hat der Angreifer bis exp Zugriff.
Lösung: kurze Access-Token-Lifetime + langlebiger Refresh-Token zum Erneuern.
Das Pattern in 4 Schritten
- Login: User authentifiziert sich (Passwort, 2FA), bekommt Access-Token (5-15 min) + Refresh-Token (7-30 Tage).
- Normale API-Calls: Client schickt Access-Token. Stateless-Verifikation. Schnell.
- Access-Token läuft ab: Client schickt Refresh-Token an
/token-Endpoint, bekommt neuen Access-Token (+ optional neuen Refresh-Token bei Rotation). - Refresh-Token läuft ab oder wird revoziert: User muss sich neu einloggen.
Access-Token-Lifetime: 5-15 Minuten
Warum so kurz?
- Begrenzt das Schadensfenster bei Kompromittierung
- Permission-Updates schlagen schnell durch (max. 15 min Latenz)
- Logout-Latenz ist akzeptabel (15 min bis "alles tot")
Zu kurz (z.B. 1 min) erhöht die /token-Calls, was bei sehr aktiven Usern Last erzeugt. 10 min ist ein guter Default.
Refresh-Token-Lifetime: 7-30 Tage
Das ist die "Re-Login-Frequenz" für aktive User. Inaktive User müssen sich nach Ablauf des Refresh-Tokens neu einloggen - das ist gewollt.
Bei sicherheits-kritischen Apps (Banking, Healthcare): 1-7 Tage. Bei Consumer-Apps: 30-90 Tage. Sliding-Window-Variante: jeder Refresh setzt expires_at neu, max. absolute Lifetime z.B. 6 Monate.
Storage: wo wohnen die zwei Tokens?
| Token | Storage | Begründung |
|---|---|---|
| Access-Token | JS-Memory (bei SPA) oder httpOnly-Cookie | Kurze Lifetime, XSS-Risiko überschaubar |
| Refresh-Token | httpOnly + Secure + SameSite=Strict Cookie | Lange Lifetime → XSS-Schutz Pflicht |
localStorage für Refresh-Token ist verboten - XSS würde es klauen, Angreifer hätte tagelangen Zugang.
Rotation: Refresh-Token wird bei jedem Refresh ersetzt
Pattern: bei jedem /token-Call wird auch der Refresh-Token erneuert. Alter Refresh-Token wird markiert als "revoked". Wenn er nochmal verwendet wird (von einem Angreifer mit Kopie) → Reuse erkannt → ganze Familie revozieren.
Detail-Implementierung siehe Case-Study Refresh-Rotation.
/token-Endpoint Logik
POST /token
Body: { refresh_token: "rt_abc123..." }
Server:
1. Refresh-Token hashen, in DB lookup
2. Wenn nicht gefunden → 401
3. Wenn revoked_at gesetzt → ALARM: alle Tokens der Familie revozieren, 401
4. Wenn expires_at < now → 401
5. Sonst:
- alten Refresh-Token markieren als revoked
- neuen Refresh-Token ausstellen (gleiche family_id)
- neuen Access-Token signieren
- beide returnen
Concurrent-Refresh-Problem
Edge-Case: User öffnet App in zwei Tabs. Beide bemerken gleichzeitig, dass Access-Token abgelaufen ist, schicken parallel /token-Requests mit demselben Refresh-Token.
Naive Implementierung: erster Request gewinnt, zweiter sieht "revoziert" → Reuse-Alarm → User wird ausgeloggt obwohl alles legit war.
Lösung: 5-10s Toleranz-Fenster. In dem Zeitraum: zweiter Request bekommt den schon ausgestellten neuen Refresh-Token (statt Reuse-Alarm). Implementierung: revoked_replacement_token im DB-Eintrag merken.
Logout-Endpoint
POST /logout
- Refresh-Token aus Cookie lesen
- In DB als revoked markieren
- Cookie löschen (Set-Cookie mit Max-Age=0)
- Access-Token? Bleibt bis exp gültig (max 10 min)
Wer "alle Geräte ausloggen" implementieren will: alle nicht-revozierten Refresh-Tokens des Users in einem Query revozieren.
Was im Access-Token drinsteht
{
"iss": "https://auth.example.com",
"sub": "user_42",
"aud": "https://api.example.com",
"exp": 1736246490, // jetzt + 10 min
"iat": 1736245890,
"scope": "read:profile write:profile",
"role": "user"
}
Was NICHT drin steht: refresh_token-ID, Passwort, sensible Profile-Daten. Access-Token muss minimal und cacheable bleiben.
OAuth-2.0 Konformität
Wer OAuth-2.0-konform sein will, sollte sich an die "OAuth 2.0 Security Best Current Practice" (draft-ietf-oauth-security-topics) halten. Sentence-summary: kurze Access-Tokens, Refresh-Token-Rotation, Reuse-Detection, PKCE für Public Clients, kein Resource-Owner-Password-Credentials-Grant mehr.
Im JWT Decoder lässt sich jedes Access-Token zerlegen und der exp-Claim live gegen die Uhr prüfen. Refresh-Tokens sind meist opake Strings, nicht JWTs - die kann der Decoder nicht analysieren.