quarkusio/quarkus · error · IllegalStateException

Current principal ${principal} is not a JSON web token

Error message

Current principal ${principal} is not a JSON web token

What it means

The JwtPrincipalProducer resolves the current security identity and returns its principal as a JsonWebToken; anonymous identities get a NullJsonWebToken sentinel. If the identity is authenticated but its principal is not a JsonWebToken (i.e. the request was authenticated by a mechanism other than SmallRye JWT), the producer throws this IllegalStateException when JsonWebToken is produced into the application.

Source

Thrown at extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/JwtPrincipalProducer.java:36

    @Inject
    SecurityIdentity identity;

    /**
     * The producer method for the current JsonWebToken
     *
     * @return JsonWebToken
     */
    @Produces
    @RequestScoped
    JsonWebToken currentJWTPrincipalOrNull() {
        if (identity.isAnonymous()) {
            return new NullJsonWebToken();
        }
        if (identity.getPrincipal() instanceof JsonWebToken) {
            return (JsonWebToken) identity.getPrincipal();
        }
        throw new IllegalStateException("Current principal " + identity.getPrincipal() + " is not a JSON web token");
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure the request is actually authenticated via quarkus-smallrye-jwt (mp.jwt.verify.* / quarkus.smallrye-jwt config) so the principal is a JsonWebToken
  2. If OIDC is the real mechanism, consume the OIDC identity instead of JsonWebToken
  3. Guard the injection point: inject SecurityIdentity and check getPrincipal() instanceof JsonWebToken before use
  4. Fix test security setup to provide a JWT principal when testing JWT paths

Example fix

// before
@Inject JsonWebToken jwt; // fails for non-JWT auth mechanisms

// after
@Inject SecurityIdentity identity;

String upn() {
    if (identity.getPrincipal() instanceof JsonWebToken jwt) {
        return jwt.getSubject();
    }
    return identity.getPrincipal().getName();
}
Defensive patterns

Strategy: type-guard

Validate before calling

@Inject SecurityIdentity identity;

JsonWebToken jwtOrNull() {
    return identity.getPrincipal() instanceof JsonWebToken jwt ? jwt : null;
}

Type guard

static boolean isJwtPrincipal(SecurityIdentity identity) {
    return !identity.isAnonymous() && identity.getPrincipal() instanceof JsonWebToken;
}

Try / catch

try {
    JsonWebToken jwt = jwtPrincipalProducer.currentJWTPrincipalOrNull();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("is not a JSON web token")) {
        log.warn("Request not authenticated via JWT; falling back to generic principal");
        return identity.getPrincipal().getName();
    }
    throw e;
}

Prevention

When it happens

Trigger: Injecting JsonWebToken (or calling this producer) in a request authenticated by Basic auth, form auth, OIDC bearer token authentication, or any non-smallrye-jwt mechanism — identity.getPrincipal() is then not a JWT.

Common situations: Mixed authentication setups where some endpoints use quarkus-oidc bearer auth and code also injects JsonWebToken; Basic-auth protected management endpoints with JWT-injecting beans; testing with TestSecurity using a non-JWT principal; JWT auth disabled by misconfiguration while code assumes it.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/430647ee6e5b7f0c. Report an issue: GitHub.