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

  1. Re-authenticate to obtain a new token that includes exp: 'cscli capi delete' + 'cscli capi register', then login.
  2. Ensure any token provisioning tooling issues standard JWTs with a numeric Unix-seconds exp claim.
  3. 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

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.