Tencent/WeKnora · error
token lifetime exceeds %s
Error message
token lifetime exceeds %s
What it means
verifyExternalUserJWT in internal/middleware/auth.go:643 rejects tokens whose time until expiration exceeds maxExternalUserTokenTTL. Even correctly signed, unexpired tokens are refused if their total remaining lifetime is too long, capping how long a stolen token remains usable.
Source
Thrown at internal/middleware/auth.go:643
)
token, err := parser.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret), nil
})
if err != nil {
return "", err
}
if token == nil || !token.Valid {
return "", errors.New("invalid external user token")
}
exp, err := claims.GetExpirationTime()
if err != nil || exp == nil {
return "", errors.New("missing expiration")
}
if time.Until(exp.Time) > maxExternalUserTokenTTL {
return "", fmt.Errorf("token lifetime exceeds %s", maxExternalUserTokenTTL)
}
if nbf, nbfErr := claims.GetNotBefore(); nbfErr == nil && nbf != nil && time.Now().Before(nbf.Time) {
return "", errors.New("token not yet valid")
}
if got := principalTenantIDFromClaims(claims); got != tenantID {
return "", fmt.Errorf("workspace mismatch: got %d want %d", got, tenantID)
}
sub, _ := claims["sub"].(string)
sub = strings.TrimSpace(sub)
if sub == "" {
return "", errors.New("missing subject")
}
return sub, nil
}
func validateExternalUserID(id string) error {
id = strings.TrimSpace(id)
if id == "" {View on GitHub (pinned to 988cbb0330)
Solutions
- Shorten the token lifetime at issuance to at most maxExternalUserTokenTTL.
- Implement token refresh instead of long-lived tokens.
- If the business case truly needs longer TTLs, adjust maxExternalUserTokenTTL deliberately (security trade-off).
Example fix
// before claims["exp"] = time.Now().Add(720 * time.Hour).Unix() // exceeds TTL // after claims["exp"] = time.Now().Add(10 * time.Minute).Unix() // within maxExternalUserTokenTTL
Defensive patterns
Strategy: validation
Validate before calling
exp := time.Now().Add(lifetime)
if lifetime > maxExternalUserTokenTTL { // shorten before signing
lifetime = maxExternalUserTokenTTL
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "token lifetime exceeds") {
// mint a shorter-lived token
}
} Prevention
- Default to short-lived tokens (minutes) plus refresh flows.
- Align issuer TTL config with server maxExternalUserTokenTTL.
- Unit-test issued tokens against the server TTL before rollout.
When it happens
Trigger: A validly signed HS256 token for the right tenant/audience has exp further in the future than maxExternalUserTokenTTL; resolveAPIPrincipal surfaces it wrapped as errInvalidExternalUserToken.
Common situations: Issuer configures 30-day token lifetimes while the server enforces a short TTL; long-lived "API tokens" reused as external user tokens.
Related errors
- unexpected signing method: %v
- join request not found
- failed to retrieve: %s
- opensearch: index not found
- 2201
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/97e505896433075f.
Report an issue: GitHub.