Ratgeber · JWT 2026
JWT im Browser sicher speichern
localStorage ist XSS-anfällig, httpOnly-Cookies sind XSS-sicher aber CSRF-relevant. Empfehlung: Cookie + SameSite=Strict + CSRF-Token.
Drei Optionen, alle mit Trade-offs
Wer JWT-basierte Auth im Browser implementiert, muss entscheiden: wo wohnt der Token? Drei Standard-Optionen, je mit Sicherheits-Trade-off.
Option 1: localStorage
localStorage.setItem('access_token', token);
const t = localStorage.getItem('access_token');
fetch('/api/data', { headers: { Authorization: 'Bearer ' + t } });
Vorteile: einfach, persistent über Page-Reloads, kein Server-Setup nötig.
Nachteil: XSS-anfällig. Jeder JavaScript-Code der Origin kann localStorage lesen. Wenn ein Angreifer XSS einschleust (third-party-Script, dependency-Vulnerability, Markdown-Renderer-Bug), kann er den Token klauen und exfiltrieren.
Empfehlung: NIE für Refresh-Tokens. Für kurzlebige Access-Tokens (≤ 15 min) noch akzeptabel, wenn XSS-Hardening sonst stimmt.
Option 2: sessionStorage
Wie localStorage, nur dass der Token mit dem Tab geschlossen wird. Gleiches XSS-Problem. sessionStorage ist auch nicht "sessionStorage = Server-Session"-sicher - der Name ist irreführend, es ist nur "Per-Tab-localStorage".
Empfehlung: selten sinnvoll. Wer Persistenz nicht will, kann den Token einfach in JavaScript-Memory halten (siehe Option 4).
Option 3: httpOnly-Cookie
// Server-Response
Set-Cookie: access_token=eyJhbGc...;
HttpOnly;
Secure;
SameSite=Strict;
Path=/;
Max-Age=900
Vorteile:
- HttpOnly: JavaScript kann nicht zugreifen → XSS-sicher
- Secure: nur über HTTPS
- SameSite=Strict: nicht von cross-origin Sites mitgesendet → CSRF-Schutz
- Browser sendet Cookie automatisch bei jedem Request - kein JS-Code für Header-Setting nötig
Nachteil:
- CSRF-Relevanz: bei SameSite=Lax oder None müssen CSRF-Tokens zusätzlich gesetzt werden
- Subdomain-Komplikationen: api.example.com vs www.example.com brauchen sorgfältiges Domain-Cookie-Setup
- CORS: bei Cross-Origin-API muss credentials: 'include' gesetzt sein, Server CORS-Config muss stimmen
Empfehlung: Default-Wahl für Refresh-Tokens. Auch für Access-Tokens gut, wenn die Same-Origin-Anforderung erfüllt ist.
Option 4: JS-Memory (in-app Variable)
// React-Beispiel
const [accessToken, setAccessToken] = useState(null);
// nach Login:
setAccessToken(receivedToken);
// bei Logout oder Page-Reload: weg
Vorteile: kein XSS-Persistenz-Vektor (Token überlebt Page-Reload nicht), beste Sicherheit für Access-Tokens.
Nachteil: nach Page-Reload weg. User muss sich neu einloggen - außer es gibt einen Refresh-Token im httpOnly-Cookie, der den Access-Token wiederherstellen kann.
Empfehlung: ideale Wahl für kurzlebige Access-Tokens in Kombination mit httpOnly-Cookie für Refresh-Token.
Empfohlene Architektur
| Token-Typ | Storage | Begründung |
|---|---|---|
| Access-Token (5-15 min) | JS-Memory | XSS-Schaden minimal (kurze Lifetime), nicht persistent |
| Refresh-Token (7-30 Tage) | httpOnly + Secure + SameSite=Strict Cookie | Persistent UND XSS-sicher |
Beim Page-Reload: kein Access-Token, aber Refresh-Cookie wird automatisch mitgesendet. Client ruft /token auf, bekommt neuen Access-Token, läuft weiter.
Anti-Pattern: Token aus Cookie in JS auslesen
// FALSCH: extrahiere JWT aus document.cookie und nutze in Header
const token = document.cookie.match(/access_token=([^;]+)/)[1];
fetch('/api', { headers: { Authorization: 'Bearer ' + token } });
Das geht nur, wenn der Cookie NICHT httpOnly ist. Aber dann ist der XSS-Schutz weg.
Anti-Pattern: zwei Locations gleichzeitig
Manche Setups speichern den Token sowohl in Cookie als auch in localStorage. "Belt and suspenders". Tatsächlich: das schlechtere von beiden Welten - XSS klaut aus localStorage, CSRF nutzt den Cookie.
Mobile-Apps
iOS Keychain bzw. Android Keystore sind die richtigen Storage-Layer für Mobile. Bei Hybrid-Apps (Cordova, Capacitor, React Native): Plugin nutzen, das Native-Storage ansteuert. Nicht localStorage in einer WebView.
Kontroverse: localStorage ist "OK" für viele Sites
Manche Security-Experten argumentieren, dass XSS-Hardening sowieso Pflicht ist (Content-Security-Policy, sanitization, dependency-audit) und die Diskussion um localStorage vs Cookie eine Ablenkung sei. Auch korrekt: wenn XSS möglich ist, kann ein Angreifer auch ohne Token klauen einfach im User-Context handeln.
Aber: Defense-in-Depth. httpOnly-Cookie ist eine zusätzliche Verteidigungsschicht, kostenlos im Setup. Es gibt keinen guten Grund, sie wegzulassen.
Im JWT Decoder wird kein Token irgendwo gespeichert - alles passiert clientseitig in JavaScript-Memory, weg nach Page-Reload.