JWT Tokens Explained: Structure, Security & Decoding

Understand JSON Web Tokens from the inside out. Learn the header, payload, and signature structure, common claims, signing algorithms, and security best practices.

JSONTech-TeamFebruary 1, 202510 min read

Was ist ein JWT?

Ein JSON Web Token (JWT, ausgesprochen „jot“) ist eine kompakte, URL-sichere Zeichenkette, die Claims zwischen zwei Parteien darstellt. Es ist die gängigste Methode für Authentifizierung und Autorisierung in modernen Webanwendungen.

Wenn Sie sich bei einer Web-App anmelden und der Server Ihnen ein Token zurückgibt, anstatt eine serverseitige Session anzulegen, handelt es sich mit großer Wahrscheinlichkeit um ein JWT. Ihr Browser sendet es bei jeder weiteren Anfrage mit, und der Server prüft die Signatur, ohne die Datenbank abzufragen.

Wo JWTs eingesetzt werden

  • Authentifizierung. Nach der Anmeldung stellt der Server ein JWT aus. Der Client speichert es und sendet es bei jeder Anfrage im Header Authorization mit.
  • Single Sign-On (SSO). JWTs ermöglichen es Nutzern, sich einmal anzumelden und mehrere Dienste zu nutzen. Identitätsanbieter wie Auth0, Okta und Keycloak stellen JWTs aus, die nachgelagerte Dienste eigenständig verifizieren können.
  • API-Autorisierung. Microservices reichen JWTs untereinander weiter, um nachzuweisen, dass eine Anfrage im Namen eines authentifizierten Nutzers mit bestimmten Berechtigungen erfolgte.
  • Informationsaustausch. Da JWTs signiert sind, können sie vertrauenswürdige Daten zwischen Parteien transportieren, ohne einen zusätzlichen Verifizierungsschritt.

Die drei Teile eines JWT

Jedes JWT besteht aus drei Base64URL-kodierten Teilen, die durch Punkte getrennt sind:

header.payload.signature

Hier ist ein echtes JWT (zur besseren Lesbarkeit gekürzt):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Dekodieren wir jeden Teil.

Teil 1: Header

Der Header beschreibt den Tokentyp und den Signaturalgorithmus. Aus Base64URL dekodiert:

{ "alg": "HS256", "typ": "JWT" }

alg teilt dem Verifizierer mit, welcher Algorithmus zu verwenden ist. typ bestätigt, dass es sich um ein JWT handelt.

Teil 2: Payload (Claims)

Der Payload enthält die Claims — die eigentlichen Daten, die das Token transportiert. Dekodiert:

{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }

Claims sind Schlüssel-Wert-Paare. Einige sind standardisiert („registered claims“), eigene Claims können ergänzt werden.

Der Payload ist Base64URL-kodiert, nicht verschlüsselt. Jeder, der das Token hat, kann den Payload dekodieren und lesen. Legen Sie niemals Geheimnisse, Passwörter oder sensible personenbezogene Daten in einen JWT-Payload.

Teil 3: Signatur

Die Signatur wird berechnet, indem der kodierte Header, ein Punkt, der kodierte Payload genommen und mit einem geheimen Schlüssel signiert wird:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Die Signatur garantiert, dass das Token nicht manipuliert wurde.

Selbst ausprobieren: Fügen Sie ein beliebiges JWT in unseren JWT Decoder ein, um alle drei Teile sofort zu inspizieren.

Häufige JWT-Claims

ClaimVollständiger NameBeschreibung
subSubjectWorum es im Token geht (meist eine Nutzer-ID)
issIssuerWer das Token ausgestellt hat (z. B. die URL Ihres Auth-Servers)
audAudienceVorgesehener Empfänger (z. B. die URL Ihrer API)
expExpiration TimeUnix-Zeitstempel, nach dem das Token ungültig ist
iatIssued AtUnix-Zeitstempel der Token-Erstellung
nbfNot BeforeToken ist vor diesem Unix-Zeitstempel ungültig
jtiJWT IDEindeutige Kennung zur Verhinderung der Token-Wiederverwendung

Eigene Claims sind alles, was Sie zusätzlich definieren. Halten Sie eigene Claims schlank.

Signaturalgorithmen im Vergleich

AlgorithmusTypSchlüsselAm besten geeignet für
HS256Symmetrisch (HMAC)Ein gemeinsames GeheimnisEinfache Setups, bei denen Aussteller und Verifizierer derselbe Dienst sind
RS256Asymmetrisch (RSA)Privater Schlüssel signiert, öffentlicher verifiziertVerteilte Systeme, SSO
ES256Asymmetrisch (ECDSA)Privater Schlüssel signiert, öffentlicher verifiziertWie RS256, aber kleinere Schlüssel und schneller

Symmetrisch (HS256) ist einfacher: Beide Seiten teilen dasselbe Geheimnis. Asymmetrisch (RS256, ES256) eignet sich besser für verteilte Architekturen.

Sicherheits-Best Practices

  • Niemals Geheimnisse im Payload ablegen. Verwenden Sie JWE, wenn Sie verschlüsselte Tokens benötigen.
  • Kurze Gültigkeitsdauer nutzen. 5–15 Minuten für Access-Tokens.
  • Immer HTTPS verwenden.
  • Alle Claims validieren. Prüfen Sie stets exp, iss und aud.
  • alg: none nicht akzeptieren.
  • Eine Positivliste für Algorithmen verwenden.
  • Tokens sicher speichern. HttpOnly-Cookies sind sicherer als localStorage.

Typische JWT-Fehler

  • JWT in der URL. Stattdessen den Header Authorization oder ein Cookie verwenden.
  • Signatur gar nicht prüfen. Ein Angreifer kann beliebige Tokens fälschen.
  • Schwaches Geheimnis für HS256. Verwenden Sie eine kryptografisch zufällige Zeichenkette mit mindestens 256 Bit.
  • Tokens ohne Ablauf. Ohne Schlüsselwechsel keine sinnvolle Widerrufsmöglichkeit.
  • Zu viele Daten im Token. Ein 4-KB-Token belastet jeden API-Aufruf.

Ablauf Token-Refresh

  1. Nutzer meldet sich an. Der Server liefert Access-Token (kurzlebig, z. B. 15 Minuten) und Refresh-Token (langlebig, z. B. 7 Tage).
  2. Der Client sendet das Access-Token bei jeder API-Anfrage im Header Authorization: Bearer.
  3. Wenn das Access-Token abläuft, antwortet die API mit 401.
  4. Der Client sendet das Refresh-Token an den Endpunkt /refresh.
  5. Der Server validiert und stellt ein neues Access-Token aus (optional neues Refresh-Token — Refresh-Token-Rotation).
  6. Der Client wiederholt die Anfrage mit dem neuen Access-Token.
// Simplified refresh flow (client-side)
const handleApiRequest = async (url, options) => {
  let response = await fetch(url, {
    ...options,
    headers: { ...options.headers, Authorization: `Bearer ${getAccessToken()}` },
  });
  if (response.status === 401) {
    const refreshResponse = await fetch("/api/refresh", {
      method: "POST",
      body: JSON.stringify({ refresh_token: getRefreshToken() }),
    });
    if (refreshResponse.ok) {
      const { access_token, refresh_token } = await refreshResponse.json();
      saveTokens(access_token, refresh_token);
      response = await fetch(url, {
        ...options,
        headers: { ...options.headers, Authorization: `Bearer ${access_token}` },
      });
    } else { redirectToLogin(); }
  }
  return response;
};

JWTs vs. Sessions: Wann was nutzen

AspektJWTServerseitige Sessions
ZustandsspeicherungClient (zustandsloser Server)Server (Session-Store / Datenbank)
SkalierbarkeitEinfach — kein geteilter Zustand zwischen ServernErfordert gemeinsamen Session-Store (Redis, DB)
WiderrufSchwer — Blockliste oder kurze Laufzeit nötigEinfach — Session im Store löschen
Payload-GrößeGrößer (Claims in jeder Anfrage)Kleiner (nur Session-ID-Cookie)
Cross-DomainGut geeignet (als Bearer-Token)Erfordert CORS-/Cookie-Konfiguration
MicroservicesIdeal — jeder Dienst verifiziert eigenständigJeder Dienst muss den Session-Store abfragen
EinfachheitMehr Bausteine (Signierung, Refresh-Flow)Einfacher korrekt umzusetzen

JWTs nutzen für zustandslose Authentifizierung über verteilte Dienste, mobile Apps oder Drittanbieter-API-Nutzer. Sessions nutzen für einfachen Widerruf, einzelne monolithische Apps oder die einfachste sichere Variante.

Selbst ausprobieren: Dekodieren und inspizieren Sie jedes JWT sofort mit unserem JWT Decoder — keine Daten verlassen Ihren Browser.

Verwandte Tools