SigNoz/signoz · error

errors.CodeUnauthenticated

errors.CodeUnauthenticated

Error message

failed to parse jwt token

What it means

getClaimsFromToken parses a JWT using the provider's configured secret as the HMAC key and throws this unauthenticated error when parsing or signature verification fails. It is the common failure path behind GetIdentity, RotateToken, and SetLastObservedAt, so any token-validation problem surfaces here with the underlying jwt error wrapped.

Source

Thrown at pkg/tokenizer/jwttokenizer/provider.go:210

		}
	}

	return stats, nil
}

func (provider *provider) getClaimsFromToken(token string) (Claims, error) {
	claims := Claims{}

	_, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unrecognized signing algorithm: %s", token.Method.Alg())
		}

		return []byte(provider.config.JWT.Secret), nil
	})

	if err != nil {
		return Claims{}, errors.Wrapf(err, errors.TypeUnauthenticated, errors.CodeUnauthenticated, "failed to parse jwt token")
	}

	return claims, nil
}

func (provider *provider) Stop(ctx context.Context) error {
	close(provider.stopC)
	return nil
}

func (provider *provider) ListMaxLastObservedAtByOrgID(ctx context.Context, orgID valuer.UUID) (map[valuer.UUID]time.Time, error) {
	userIDToLastObservedAts := provider.listLastObservedAtDesc(orgID)

	maxLastObservedAtPerUserID := make(map[valuer.UUID]time.Time)

	for _, userIDToLastObservedAt := range userIDToLastObservedAts {
		for userID, lastObservedAt := range userIDToLastObservedAt {
			if lastObservedAt.IsZero() {

View on GitHub (pinned to 5069bf80b0)

Solutions

  1. Decode the wrapped jwt error: 'signature is invalid' points to a secret mismatch, 'token is expired' to expiry, 'token contains an invalid number of segments' to a malformed/non-JWT string
  2. Ensure all services minting and validating tokens use the same JWT.Secret configuration value
  3. If the secret was rotated, force clients to re-authenticate and obtain fresh tokens (old tokens will fail by design)
  4. Verify the token is a well-formed JWT (three base64url segments) and not an opaque token or API key
  5. Check server clocks (NTP) if expiry/nbf failures look spurious

Example fix

// before
identity, err := provider.GetIdentity(ctx, "some-opaque-api-key")

// after
identity, err := provider.GetIdentity(ctx, jwtString) // must be a JWT signed with provider.config.JWT.Secret
if errors.Ast(err, errors.TypeUnauthenticated) { /* re-auth / 401 */ }
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap structural pre-check before calling identity APIs:
func looksLikeJWT(s string) bool {
    parts := strings.Split(s, ".")
    return len(parts) == 3
}

Type guard

func isParsableJWT(s string) bool { return looksLikeJWT(s) }

Try / catch

claims, err := provider.GetIdentity(ctx, token)
if err != nil {
    if errors.Ast(err, errors.TypeUnauthenticated) {
        // 401: distinguish via wrapped jwt error (signature vs expiry) for logging; client must re-auth
    }
    return err
}

Prevention

When it happens

Trigger: Calling GetIdentity/RotateToken/SetLastObservedAt with a malformed, tampered, or wrong-issuer/audience token, an expired token, or a token signed with a different secret than provider.config.JWT.Secret (e.g. token minted by another environment). Algorithm mismatches (token alg RS256 while the parser expects HS256 with a byte-secret) also land here.

Common situations: JWT_SECRET rotated or differing between services/environments, stale tokens held by clients after a secret change, clock skew causing expiry validation failures, or passing an opaque API key where a JWT is expected.

Understand the failure class

Related errors


AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28). Data as JSON: /api/errors/9be5cf0fe765a66e. Report an issue: GitHub.