Wenn eine API token expired, jwt expired oder invalid_token meldet, prüfe ich zuerst, ob das Token wirklich außerhalb seines Zeitfensters liegt. Ich unterscheide zwischen echter Expiration, Clock Skew, zusätzlicher Server-Policy und einer generischen 401-Meldung, die nur zufällig wie ein Zeitproblem aussieht.
Für die schnelle Sichtung nutze ich den JWT Expiry Checker, weil er exp, iat und nbf in lesbare UTC-Zeiten umwandelt.
Schritt 1: exp korrekt interpretieren
JWT NumericDate verwendet Sekunden seit Unix Epoch:
{
"iat": 1789200000,
"exp": 1789203600
}
In JavaScript muss ich deshalb Millisekunden berücksichtigen:
const expiresAtMs = payload.exp * 1000;
const expired = Date.now() >= expiresAtMs;
Ein Vergleich von Date.now() direkt mit einem zehnstelligen exp ist ein Einheitenfehler und kann das Debugging komplett in die falsche Richtung schicken.
Schritt 2: Die Uhr des Verifiers ist entscheidend
Nicht die Uhr meines Laptops entscheidet, ob die API akzeptiert. Maßgeblich ist die Zeit auf dem System, das validiert: API, Gateway, Service Mesh oder Identity-Aware Proxy.
Ich vergleiche:
Token exp 2026-09-16T12:00:00Z
API time 2026-09-16T12:00:07Z
clock leeway 5s
Ergebnis abgelaufen
Wenige Sekunden am Rand können Clock Skew sein. 30 oder 60 Minuten Differenz sind kein plausibler Skew-Fall.
Schritt 3: nbf, iat und zusätzliche Altersregeln mitprüfen
Ein Token kann zeitlich scheitern, obwohl exp in der Zukunft liegt:
nbfliegt noch in der Zukunft;iatist wegen falscher Serverzeit auffällig;- die Anwendung erzwingt ein maximales Token-Alter;
- Session-/Revocation-Policy beendet die Gültigkeit vor
exp.
Ich behandle exp deshalb als eine Validierungsregel, nicht als vollständiges Urteil. Der JWT Validator hilft dabei, Signatur und Claims gemeinsam zu prüfen.
Schritt 4: Die tatsächliche Servermeldung lesen
RFC 6750 verwendet bei Bearer Tokens invalid_token unter anderem für abgelaufene, widerrufene oder anderweitig ungültige Tokens. Deshalb ist diese Meldung allein nicht präzise genug.
Typische Hinweise sind:
401 Unauthorized
invalid_token
token expired
jwt expired
TokenExpiredError
signature has expired
Wenn Logs ausdrücklich Expiration nennen und die Zeitwerte passen, ist die Ursache klar. Ist die Meldung generisch, gehe ich weiter zu Signatur, Issuer und Audience.
Schritt 5: Refresh oder Reauthentication auswählen
Ich verlängere ein signiertes JWT nicht durch Editieren von exp. Das würde die Payload-Bytes ändern und die bestehende Signatur ungültig machen.
Meine Entscheidung sieht so aus:
| Situation | Aktion |
|---|---|
| Access Token abgelaufen, gültiger Refresh Flow vorhanden | neues Access Token anfordern |
| Refresh Token abgelaufen/widerrufen | neu authentifizieren |
| Kein Refresh Flow vorgesehen | neu authentifizieren oder Client Flow erneut ausführen |
| Service verwendet Client Credentials | neues Token beim Authorization Server holen |
| Token noch nicht abgelaufen | andere Validierungsursache untersuchen |
Warum parallele Refreshes zu Folgefehlern führen können
In Browser- oder Mobile-Apps sehe ich manchmal mehrere Requests gleichzeitig mit einem gerade ablaufenden Token. Wenn jeder Request unabhängig einen Refresh startet, können Race Conditions entstehen. Je nach System wird ein Refresh Token rotiert und der zweite parallele Refresh schlägt dann bereits fehl.
Die Lösung liegt in der Client-Session-Logik: Refresh koordinieren, neue Tokens atomar übernehmen und alte Access Tokens nicht weiterverwenden.
Ein abgelaufenes Token kann eine gültige Signatur haben
Das ist kein Widerspruch:
signature valid ✓
issuer valid ✓
audience valid ✓
expiration valid ✕
Die Signatur beweist Integrität und Authentizität gegenüber einem vertrauenswürdigen Schlüssel. Expiration begrenzt das Akzeptanzfenster. Genau deshalb trenne ich Signaturprüfung und Zeitvalidierung gedanklich.
Wenn exp fehlt
RFC 7519 definiert exp, aber nicht jedes JWT-Profil verlangt den Claim zwingend. Ich prüfe die konkrete Anwendung oder das Token-Profil.
Für kurzlebige Bearer Access Tokens ist fehlende Expiration für mich ein Policy-Signal, das ich untersuche. Ich erfinde aber keine universelle Regel „JWT ohne exp ist syntaktisch ungültig“.
Was ich bei scheinbar zu früher Expiration prüfe
- API-/Gateway-Uhr und NTP-Synchronisation.
- Identity-Provider-Uhr.
- Sekunden-vs.-Millisekunden-Fehler.
- Konfigurierte Clock Tolerance.
- Maximales Token-Alter zusätzlich zu
exp. - Falsches Environment oder falsches Token im Client Cache.
- Server-Logs für Revocation/Session-Policy.
Eine große Clock Tolerance ist kein Ersatz für synchronisierte Systeme.
Mein Recovery-Workflow
- Ich öffne den JWT Expiry Checker.
- Ich bestätige
exp,iatundnbfals NumericDate in Sekunden. - Ich vergleiche
expmit der Uhr des tatsächlich ablehnenden Verifiers. - Ich lese den
WWW-Authenticate-Header und Server-Logs, falls vorhanden. - Ich bestätige, ob es echte Expiration oder eine andere
invalid_token-Ursache ist. - Bei echter Expiration nutze ich den vorgesehenen Refresh-/Reauthentication-Flow.
- Ich editiere
expnicht und verwende keine alte Signatur weiter. - Ist das Token zeitlich aktiv, prüfe ich Signatur,
issundaudmit dem JWT Debugger.
Die wichtigste Unterscheidung lautet: „abgelaufen“ bedeutet nicht „beschädigt“. Ein Token kann technisch korrekt und authentisch sein und trotzdem außerhalb seines erlaubten Zeitfensters liegen.