{"record":{"id":"94e06a111b5aef82","repo":"grpc/grpc-go","slug":"expired-token","errorCode":null,"errorMessage":"expired token","messagePattern":"expired token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/jwt/file_reader.go","lineNumber":114,"sourceCode":"\tpayloadBytes, err := base64.RawURLEncoding.DecodeString(claimsRaw)\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"decode error: %v\", err)\n\t}\n\n\tvar claims jwtClaims\n\tif err := json.Unmarshal(payloadBytes, &claims); err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"unmarshal error: %v\", err)\n\t}\n\n\tif claims.Exp == 0 {\n\t\treturn time.Time{}, fmt.Errorf(\"no expiration claims\")\n\t}\n\n\texpTime := time.Unix(claims.Exp, 0)\n\n\t// Check if token is already expired.\n\tif expTime.Before(time.Now()) {\n\t\treturn time.Time{}, fmt.Errorf(\"expired token\")\n\t}\n\n\treturn expTime, nil\n}\n","sourceCodeStart":96,"sourceCodeEnd":119,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/jwt/file_reader.go#L96-L119","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func tokenAlive(path string, skew time.Duration) error {\n    b, err := os.ReadFile(path)\n    if err != nil {\n        return err\n    }\n    parts := strings.Split(strings.TrimSpace(string(b)), \".\")\n    if len(parts) != 3 {\n        return errors.New(\"not a JWT\")\n    }\n    payload, _ := base64.RawURLEncoding.DecodeString(parts[1])\n    var c struct{ Exp int64 `json:\"exp\"` }\n    _ = json.Unmarshal(payload, &c)\n    if time.Unix(c.Exp, 0).Before(time.Now().Add(skew)) {\n        return errors.New(\"token expired or about to expire\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// On RPC, codes.Unauthenticated with 'expired token' => refresh/redeploy:\nif status.Code(err) == codes.Unauthenticated && strings.Contains(err.Error(), \"expired token\") {\n    triggerTokenRefresh()\n}","preventionTips":["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."],"tags":["grpc","jwt","expiry","credentials","clock-skew"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}