Fehlermeldung
token has invalid claims: token is expired
Auch ausgegeben als
- Token is expired
- token has invalid claims: token is not valid yet
- token has invalid claims: token used before issued
golang-jwt v4 gibt „Token is expired“ aus (mit großem T). Die anderen Claim-Fehler von v5 verwenden dasselbe Präfix „token has invalid claims:“.
golang-jwt/jwt (Go) — jwt.ErrTokenInvalidClaims joined with jwt.ErrTokenExpired
Was der Fehler bedeutet
Die Signatur des Tokens wurde erfolgreich geprüft, aber sein Claim `exp` liegt in der Vergangenheit (jenseits jeder konfigurierten Toleranz). golang-jwt v5 meldet das als `ErrTokenInvalidClaims`, verknüpft mit `ErrTokenExpired`; dieselbe Familie erzeugt „token is not valid yet“ für ein in der Zukunft liegendes `nbf` und „token used before issued“ für ein in der Zukunft liegendes `iat`. Das geparste Token wird zusammen mit dem Fehler trotzdem zurückgegeben, ihm darf aber nicht vertraut werden.
Warum der Fehler auftritt
Das Token hat seine Laufzeit überschritten
häufigAccess Tokens sind typischerweise 5–60 Minuten gültig. Clients, die ein Token zwischenspeichern, eine Anfrage viel später wiederholen oder es in einem lang laufenden Job aufbewahren, legen es erst nach `exp` vor.
Die Uhr der prüfenden Seite geht vor
häufigEin Server, dessen Uhr vorgeht, lässt jedes Token zu früh ablaufen. Container übernehmen die Uhr des Hosts, deshalb betrifft ein einzelner Host ohne NTP alle seine Dienste.
Der Client hat keinen Weg zum Refresh
gelegentlichSingle-Page-Apps und CLIs, die ein Access Token speichern, aber das Refresh Token nie verwenden (oder 401 nie behandeln), scheitern dauerhaft, sobald das erste Token abläuft.
exp wurde in der falschen Einheit geschrieben
selten`exp` enthält Sekunden seit der Epoche. Ein Aussteller, der Millisekunden zweimal teilt oder eine Umrechnung in Ortszeit verwendet, kann Tokens ausstellen, die bereits abgelaufen sind.
So behebst du den Fehler
- 1.
Ablauf erkennen und den Client per Refresh erneuern lassen
Bilde `ErrTokenExpired` auf 401 mit dem Hinweis `invalid_token` ab. Der Client verwendet dann sein Refresh Token (oder authentifiziert sich neu) und wiederholt die Anfrage.
go token, err := jwt.Parse(raw, keyfunc, jwt.WithValidMethods([]string{"ES256"})) if errors.Is(err, jwt.ErrTokenExpired) { w.Header().Set("WWW-Authenticate", `Bearer error="invalid_token", error_description="token expired"`) http.Error(w, "token expired", http.StatusUnauthorized) // client refreshes and retries return } - 2.
Kleine Uhrenabweichung tolerieren, exp verlangen
Eine Toleranz von einigen Sekunden fängt Abweichungen zwischen Rechnern ab. `WithExpirationRequired` schließt die entgegengesetzte Lücke: Tokens ohne `exp` würden sonst nie ablaufen.
go parser := jwt.NewParser( jwt.WithValidMethods([]string{"ES256"}), jwt.WithLeeway(30*time.Second), // absorbs clock skew for exp, nbf and iat jwt.WithExpirationRequired(), // tokens without exp are rejected too )