Wie funktionieren JSON Web Tokens (JWT)?
JSON Web Tokens sind aus modernen Web-APIs kaum noch wegzudenken: Single Sign-On, OAuth-Flows, OpenID Connect, serverlose Authentifizierung — fast überall taucht das kleine, kompakte Token-Format auf. Hinter dem kryptisch wirkenden String aus drei base64url-kodierten Teilen steckt ein erstaunlich einfaches, aber sicherheitskritisches Konzept. Dieser Artikel erklärt Aufbau, Signaturen, Standard-Claims und die häufigsten Fehler.
Aufbau: Header.Payload.Signature
Ein JWT besteht aus drei base64url-kodierten Teilen, durch Punkte getrennt. Der Header ist ein kleines JSON-Objekt mit Typ-Information und dem Signatur-Algorithmus, zum Beispiel: { "alg": "HS256", "typ": "JWT" }. Der Payload (oder Claims-Set) ist ebenfalls JSON und enthält die eigentlichen Informationen über das Subjekt — User-ID, Berechtigungen, Ablaufzeit. Die Signatur sichert Header und Payload kryptografisch ab.
Wichtig: der Payload ist nur kodiert, nicht verschlüsselt. Jeder, der das Token sieht, kann den Inhalt lesen. Vertrauliche Daten gehören also nicht in den Payload. Wer Verschlüsselung braucht, nutzt JWE (JSON Web Encryption); JWT-Tokens, wie sie in der Praxis verwendet werden, sind in der Regel JWS — signiert, nicht verschlüsselt.
Signatur-Algorithmen
Im Header steht das Feld alg. Die verbreitetsten Varianten:
- HS256 (HMAC-SHA256): symmetrisch, ein gemeinsames Geheimnis zwischen Aussteller und Prüfer. Schnell und einfach, eignet sich gut, wenn beide Seiten unter eigener Kontrolle stehen.
- RS256 (RSA-SHA256): asymmetrisch, der Aussteller signiert mit einem privaten Schlüssel, beliebige Clients prüfen mit dem öffentlichen Schlüssel. Standard für OAuth-/OpenID-Identity-Provider, bei denen viele Clients Tokens validieren müssen.
- ES256 (ECDSA mit P-256 und SHA-256): elliptische Kurven, kleinere Schlüssel und Signaturen bei vergleichbarer Sicherheit zu RSA. Beliebt in mobilen und IoT-Kontexten.
- EdDSA (Ed25519): moderne Edwards-Kurven-Signatur, schnell, deterministisch und ohne klassische ECDSA-Implementierungsfallen. Wird in neueren Stacks zunehmend bevorzugt.
Standard-Claims
RFC 7519 definiert ein paar registrierte Claim-Namen, deren Bedeutung interoperabel ist:
- iss (issuer): wer hat das Token ausgestellt? Üblicherweise ein URL- oder Domain-Bezeichner.
- sub (subject): worüber spricht das Token? Meist die User-ID, gelegentlich eine Anwendung.
- aud (audience): für welche Empfänger ist das Token gedacht? Wer das Token validiert, sollte prüfen, ob er in dieser Liste steht.
- exp (expiration): UNIX-Timestamp, ab dem das Token abgelaufen ist. Bei der Prüfung zwingend einzuhalten.
- iat (issued at): UNIX-Timestamp der Ausstellung. Hilfreich, um sehr alte oder zukünftige Tokens als suspekt zu erkennen.
- jti (JWT ID): eindeutige ID des Tokens. Erlaubt, einzelne Tokens auf einer Sperrliste zu führen — wichtig für Revocation-Strategien.
Wo JWTs eingesetzt werden
In OAuth 2.0 sind Access Tokens und Refresh Tokens häufig JWTs. OpenID Connect setzt JWTs für das ID-Token ein, das dem Client Identitätsinformationen über den angemeldeten Nutzer mitteilt. APIs nutzen JWTs als Bearer-Tokens im Authorization-Header (Authorization: Bearer eyJhbGciOi...).
Der typische Lifecycle: Login schickt Username/Passwort an einen Auth-Server, der ein kurzlebiges Access-JWT (z. B. 15 Minuten) plus ein längerlebiges Refresh-Token zurückgibt. Folgeanfragen an die API tragen das Access-JWT mit, der Server prüft die Signatur und einige Claims. Läuft das Access-JWT ab, holt der Client mit dem Refresh-Token ein neues — bis die Sitzung am Auth-Server endet.
Häufige Fallen
- „alg: none"-Angriff: Bibliotheken, die alg blind vertrauen, lassen sich mit dem Wert „none" zum Akzeptieren unsignierter Tokens überreden. Die Algorithmen müssen vom Server, nicht vom Token, vorgegeben werden — etwa als explizite Whitelist.
- Fehlende exp-Prüfung: ohne aktive Validierung des exp-Claims bleibt ein einmal ausgestelltes Token unbegrenzt gültig. Jede Validierungsbibliothek bietet Optionen für Ablauf- und Clock-Skew-Prüfung.
- LocalStorage vs. HttpOnly-Cookie: ein JWT im localStorage ist via XSS auslesbar. Sicherer ist es, das Token in einem HttpOnly-, Secure-, SameSite-Cookie zu speichern — auch wenn das Cross-Origin-Setup etwas komplexer wird.
- Revocation: anders als eine klassische Session-ID lässt sich ein JWT nicht serverseitig „einfach invalidieren". Wer ein Token vor Ablauf sperren muss, braucht eine Sperrliste (jti-basiert) oder kurze Lebenszeiten plus Refresh-Tokens.
- Schwache HS256-Secrets: ein 8-Zeichen-„secret" lässt sich offline brute-forcen. HS256-Schlüssel sollten zufällig erzeugt sein und mindestens 256 Bit Entropie haben — sonst lieber gleich RS256.
Häufige Fragen
Sind JWTs verschlüsselt?
Die in der Praxis meistens gemeinten JWTs (JWS) sind signiert, aber nicht verschlüsselt. Wer den Inhalt zusätzlich schützen will, kann sie als JWE-Tokens zusätzlich verschlüsseln — das ist aber selten nötig, wenn keine sensiblen Daten im Payload liegen.
Wie unterscheiden sich Access- und Refresh-Token?
Access-Tokens sind kurzlebig (Minuten) und gehen mit jeder API-Anfrage über die Leitung. Refresh-Tokens sind länger gültig (Stunden bis Wochen), liegen sicher beim Client und werden nur benutzt, um neue Access-Tokens zu erhalten. Damit bleibt der Schaden eines gestohlenen Access-Tokens klein.
Sollte ich JWT oder Sessions verwenden?
Für klassische, server-seitig gerenderte Anwendungen sind Sessions (Cookie-basiert, Server hält den State) oft einfacher und sicherer. Für API-only-Backends, mobile Apps oder verteilte Microservices spielen JWTs ihre Stärken aus: stateless, von beliebigen Instanzen prüfbar, gut interoperabel mit OAuth-Standards.