crowdsecurity/crowdsec · error · ErrTokenMissingClaim
%w: exp
Error message
%w: exp
What it means
LoadAPICToken requires the JWT 'exp' claim. If the decoded claims lack a numeric exp (or it's not a float64 as produced by the JWT library), the error wraps ErrTokenMissingClaim with ': exp'. A token without a usable expiration is treated as unverifiable and rejected even if otherwise valid.
Source
Thrown at pkg/database/token.go:53
if token == "" {
return APICToken{}, ErrTokenNotFound
}
parser := new(jwt.Parser)
tok, _, err := parser.ParseUnverified(token, jwt.MapClaims{})
if err != nil {
return APICToken{}, fmt.Errorf("%w: %s", ErrTokenParse, err)
}
claims, ok := tok.Claims.(jwt.MapClaims)
if !ok {
return APICToken{}, ErrTokenParse
}
expFloat, ok := claims["exp"].(float64)
if !ok {
return APICToken{}, fmt.Errorf("%w: exp", ErrTokenMissingClaim)
}
exp := time.Unix(int64(expFloat), 0)
if time.Now().UTC().After(exp.Add(-1 * time.Minute)) {
return APICToken{}, ErrTokenExpired
}
return APICToken{Raw: token, ExpiresAt: exp}, nil
}
// SaveAPICToken stores the given JWT token in the local database under the appropriate config item.
func (c *Client) SaveAPICToken(ctx context.Context, token string) error {
if err := c.SetConfigItem(ctx, APICTokenKey, token); err != nil {
return fmt.Errorf("saving token: %w", err)
}
return nil
}View on GitHub (pinned to 909b515798)
Solutions
- Re-authenticate to obtain a new token that includes exp: 'cscli capi delete' + 'cscli capi register', then login.
- Ensure any token provisioning tooling issues standard JWTs with a numeric Unix-seconds exp claim.
- Don't paste manually generated tokens into the DB; use cscli.
Example fix
// caller: missing/expired claims both mean 'get a fresh token'
tok, err := c.LoadAPICToken(ctx, log)
if errors.Is(err, database.ErrTokenMissingClaim) || errors.Is(err, database.ErrTokenExpired) {
return authenticate(ctx) // issues a token with exp
} Defensive patterns
Strategy: try-catch
Type guard
func isMissingExpErr(err error) bool { return errors.Is(err, database.ErrTokenMissingClaim) } Try / catch
tok, err := client.LoadAPICToken(ctx, log)
if errors.Is(err, database.ErrTokenMissingClaim) {
log.Warn("token has no exp claim, obtaining a new one")
return reauthenticate(ctx)
} Prevention
- Only store tokens issued by the standard CAPI auth flow (they include exp).
- If minting tokens with custom tooling, always set a numeric Unix-seconds exp claim.
- Re-authenticate instead of reusing foreign-version tokens.
- Test token provisioning end-to-end after version upgrades.
When it happens
Trigger: Calling LoadAPICToken with a stored JWT whose payload omits 'exp' or has it as a string/non-numeric value — e.g. a token issued by a different/newer service version, or a hand-crafted token pasted into the DB.
Common situations: Tokens minted by a custom or misconfigured CAPI/auth service without exp; manual token injection during testing; upgrading from a version whose tokens had a different claim set.
Related errors
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/7faf2752b837db56.
Report an issue: GitHub.