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

  1. Shorten the token lifetime at issuance to at most maxExternalUserTokenTTL.
  2. Implement token refresh instead of long-lived tokens.
  3. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/97e505896433075f. Report an issue: GitHub.