Wenn ich token expired, jwt expired oder einen zeitlich verdächtigen 401 sehe, prüfe ich exp früh, aber nicht isoliert. Ich konvertiere den Claim selbst, vergleiche ihn mit der Uhr des Verifiers und lese gleichzeitig iat und nbf. So trenne ich echte Expiration von Einheitenfehlern, Clock Skew und zusätzlichen Policy-Regeln.
Für eine schnelle Sichtung nutze ich den JWT Expiry Checker.
exp ist eine NumericDate in Sekunden
RFC 7519 definiert exp als Expiration Time. NumericDate zählt Sekunden seit Unix Epoch:
{
"iat": 1789200000,
"nbf": 1789200000,
"exp": 1789203600
}
Das konzeptionelle Akzeptanzkriterium lautet:
current verifier time < exp
Sobald die Verifier-Zeit exp erreicht oder überschreitet, sollte ein Profil mit Expiration-Prüfung das Token ablehnen, abgesehen von ausdrücklich konfigurierter kleiner Clock Tolerance.
Der häufigste Implementierungsfehler: Sekunden gegen Millisekunden
JavaScript Date.now() liefert Millisekunden. JWT NumericDate liefert Sekunden:
const expiresAt = payload.exp * 1000;
const expired = Date.now() >= expiresAt;
Dieser Vergleich ist falsch:
const expired = Date.now() >= payload.exp; // falsche Einheit
In Logs erkenne ich den Fehler oft daran, dass ein zehnstelliger exp mit einem dreizehnstelligen JavaScript-Timestamp verglichen wird.
Wie ich exp in mehreren Laufzeiten prüfe
Node/Browser:
const now = Math.floor(Date.now() / 1000);
if (typeof payload.exp === "number" && now >= payload.exp) {
throw new Error("token expired");
}
Python:
import time
if isinstance(payload.get("exp"), (int, float)) and time.time() >= payload["exp"]:
raise ValueError("token expired")
Diese Beispiele erklären nur die Zeitlogik. Für echte Authentifizierung nutze ich eine Bibliothek, die Signatur, Algorithmus, Issuer und Audience ebenfalls erzwingt.
Clock Skew richtig einordnen
RFC 7519 erlaubt Implementierungen eine kleine Leeway für unvermeidbare Uhrdifferenzen. Ich nutze Toleranz nur für Randfälle, nicht als pauschale Verlängerung des Tokens.
Beispiel:
exp 12:00:00Z
verifier clock 12:00:03Z
leeway 5s
=> kann noch innerhalb der Toleranz liegen
Liegt exp dagegen 45 Minuten zurück, ist „Clock Skew“ keine sinnvolle Erklärung.
iat, nbf und exp gemeinsam lesen
Ich prüfe die Zeitachse:
issued -------- active window -------- expired
iat nbf exp
Auffällige Kombinationen sind zum Beispiel:
nbf > exp;iatdeutlich in der Zukunft;- ungewöhnlich lange Laufzeit zwischen
iatundexp; expvoriat;- alle Zeitwerte um Faktor 1000 verschoben.
Der JWT Validator hilft mir, diese Claims zusammen mit der Signatur zu prüfen.
Fehlendes exp ist nicht dasselbe wie syntaktisch ungültig
Nicht jedes JWT-Profil schreibt exp vor. RFC 7523 verlangt es beispielsweise für das dort definierte OAuth-JWT-Profil, während RFC 7519 Claims grundsätzlich profilabhängig behandelt.
Deshalb frage ich:
- Welcher Token-Typ ist das?
- Welches Profil oder welche API-Policy gilt?
- Ist
expdort verpflichtend? - Gibt es zusätzlich ein maximales Token-Alter?
Ich markiere „missing exp“ als Policy-Frage, nicht automatisch als kaputte JWT-Syntax.
Warum ein Token vor exp trotzdem abgelehnt werden kann
Ein zukünftiges exp beweist nicht, dass das Token akzeptiert werden darf. Andere Gründe sind:
- Signatur ungültig;
nbfnoch nicht erreicht;- falscher
iss; - falscher
aud; - falscher Token-Typ;
- fehlende Scopes/Rollen;
- Revocation oder Session-Policy.
Wenn die Zeit korrekt aussieht, wechsle ich bewusst die Hypothese und nutze den JWT Debugger.
Warum ich exp nicht im Payload „repariere“
Ein signiertes JWT schützt die ursprünglichen Header- und Payload-Bytes. Ändere ich:
{ "exp": 1789203600 }
zu einem späteren Wert, passt die alte Signatur nicht mehr. Ein legitimer Renewal-Prozess erzeugt ein neues Token mit neuer Signatur.
Meine Entscheidungslogik bei Zeitfehlern
| Beobachtung | Interpretation | Nächster Schritt |
|---|---|---|
now >= exp | echte Expiration wahrscheinlich | Refresh/Reauthentication |
| wenige Sekunden Differenz | Clock Skew möglich | Serverzeit/Tolerance prüfen |
nbf > now | noch nicht aktiv | Issuance/Clock prüfen |
iat weit in Zukunft | Clock/Unit-Fehler | Uhren und Einheiten prüfen |
exp fehlt | profilabhängige Policy | Token-Profil lesen |
exp in Zukunft, trotzdem 401 | andere Validierung | Signatur/iss/aud prüfen |
Mein exp-Workflow
- Ich dekodiere das Token mit dem JWT Decoder.
- Ich bestätige, dass
expnumerisch ist und in Sekunden interpretiert wird. - Ich konvertiere
expzu UTC. - Ich vergleiche mit der Uhr des tatsächlichen Verifiers.
- Ich prüfe
iatundnbfauf Widersprüche. - Ich kontrolliere eine explizite, kleine Clock Tolerance.
- Ich prüfe, ob das Token-Profil
expzwingend verlangt. - Bei echter Expiration nutze ich den vorgesehenen Renewal-Flow.
- Ist das Token aktiv, prüfe ich Signatur, Issuer und Audience statt weiter an
expzu drehen.
Für mich beantwortet exp genau eine Frage: Liegt das Token außerhalb seines deklarierten Zeitfensters? Ob die Anwendung dem Token vertrauen und es akzeptieren darf, entscheidet erst die vollständige Validierung.