grpc/grpc-go · error
expired token
Error message
expired token
What it means
Returned by extractExpiration when the token's exp time is in the past relative to the process clock. The token was structurally valid but has already expired, so the reader refuses to use it. The sentinel errJWTValidation maps to codes.Unauthenticated.
Solutions
- Trigger a token refresh/redeployment so the file holds a current token.
- Verify the token-injection sidecar/init is healthy and writing fresh tokens before exp.
- Sync the system clock (ntp/chrony) if the expiry looks premature.
- Inspect exp vs current time: date -d @$(printf '%s' "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .exp).
Defensive patterns
Strategy: validation
Validate before calling
func tokenAlive(path string, skew time.Duration) error {
b, err := os.ReadFile(path)
if err != nil {
return err
}
parts := strings.Split(strings.TrimSpace(string(b)), ".")
if len(parts) != 3 {
return errors.New("not a JWT")
}
payload, _ := base64.RawURLEncoding.DecodeString(parts[1])
var c struct{ Exp int64 `json:"exp"` }
_ = json.Unmarshal(payload, &c)
if time.Unix(c.Exp, 0).Before(time.Now().Add(skew)) {
return errors.New("token expired or about to expire")
}
return nil
} Try / catch
// On RPC, codes.Unauthenticated with 'expired token' => refresh/redeploy:
if status.Code(err) == codes.Unauthenticated && strings.Contains(err.Error(), "expired token") {
triggerTokenRefresh()
} Prevention
- Run a token-refresh sidecar/init that writes new tokens before exp.
- Sync the system clock via NTP.
- Add a startup check that fails fast on already-expired tokens.
When it happens
Trigger: The token file holds a stale token that has passed its exp; the token injector has stopped refreshing; the system clock is skewed forward; very short-lived tokens read after their window.
Common situations: Kubernetes projected token not being rotated (node issue); sidecar token agent crashed; NTP drift; deploying a token baked at build time that has since expired.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- cannot send secure credentials on an insecure connection
- credentials: audience cannot be empty
- failed to build call credentials from bootstrap for
- no expiration claims
- token file access error
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/94e06a111b5aef82.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/jwt/file_reader.go:114
payloadBytes, err := base64.RawURLEncoding.DecodeString(claimsRaw)
if err != nil {
return time.Time{}, fmt.Errorf("decode error: %v", err)
}
var claims jwtClaims
if err := json.Unmarshal(payloadBytes, &claims); err != nil {
return time.Time{}, fmt.Errorf("unmarshal error: %v", err)
}
if claims.Exp == 0 {
return time.Time{}, fmt.Errorf("no expiration claims")
}
expTime := time.Unix(claims.Exp, 0)
// Check if token is already expired.
if expTime.Before(time.Now()) {
return time.Time{}, fmt.Errorf("expired token")
}
return expTime, nil
}
View on GitHub (pinned to 0c51461d27)