jwtdecoder.de

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.

Foto von Mateusz Viola

Von Mateusz Viola

Betreiber & redaktionelle Verantwortung jwtdecoder.de

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

  1. Login: User authentifiziert sich (Passwort, 2FA), bekommt Access-Token (5-15 min) + Refresh-Token (7-30 Tage).
  2. Normale API-Calls: Client schickt Access-Token. Stateless-Verifikation. Schnell.
  3. Access-Token läuft ab: Client schickt Refresh-Token an /token-Endpoint, bekommt neuen Access-Token (+ optional neuen Refresh-Token bei Rotation).
  4. 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?

TokenStorageBegründung
Access-TokenJS-Memory (bei SPA) oder httpOnly-CookieKurze Lifetime, XSS-Risiko überschaubar
Refresh-TokenhttpOnly + Secure + SameSite=Strict CookieLange 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.

Mehr zum Thema