quarkusio/quarkus · error · io.quarkus.oidc.runtime.OIDCException

Invalid token type

Error message

Invalid token type

What it means

Quarkus OIDC's OidcUtils.validatePrimaryTokenType validates that the 'typ' header of a JWT matches the configured expected token type. If the token's typ does not equal quarkus.oidc token-type configuration (e.g. expected 'access_token' vs 'id_token' typ), OIDCException 'Invalid token type' is thrown to prevent accepting the wrong token class.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java:496

    public static void setSecurityIdentityIntrospection(Builder builder, TokenIntrospection introspectionResult) {
        if (introspectionResult != null) {
            builder.addAttribute(INTROSPECTION_ATTRIBUTE, introspectionResult);
        }
    }

    public static void setSecurityIdentityConfigMetadata(QuarkusSecurityIdentity.Builder builder,
            TenantConfigContext resolvedContext) {
        if (resolvedContext.provider().client != null) {
            builder.addAttribute(CONFIG_METADATA_ATTRIBUTE, resolvedContext.provider().client.getMetadata());
        }
    }

    public static void validatePrimaryJwtTokenType(Token tokenConfig, JsonObject tokenJson) {
        if (tokenJson.containsKey("typ")) {
            String type = tokenJson.getString("typ");
            if (tokenConfig.tokenType().isPresent() && !tokenConfig.tokenType().get().equals(type)) {
                throw new OIDCException("Invalid token type");
            } else if ("Refresh".equals(type)) {
                // At least check it is not a refresh token issued by Keycloak
                throw new OIDCException("Refresh token can only be used with the refresh token grant");
            }
        }
    }

    static Uni<Void> removeSessionCookie(RoutingContext context, OidcTenantConfig oidcConfig,
            TokenStateManager tokenStateManager) {
        List<String> cookieNames = context.get(SESSION_COOKIE_NAME);
        if (cookieNames != null) {
            LOG.debugf("Remove session cookie names: %s", cookieNames);
            StringBuilder cookieValue = new StringBuilder();
            for (String cookieName : cookieNames) {
                cookieValue.append(removeCookie(context, oidcConfig, cookieName));
            }
            return tokenStateManager.deleteTokens(context, oidcConfig, cookieValue.toString(),
                    deleteTokensRequestContext);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Set quarkus.oidc.token.token-type (or TokenConfig tokenType) to match the actual JWT 'typ' header, or remove the setting to skip this check
  2. Send the correct token type (access token instead of ID token) in the Authorization header
  3. Check the token's typ header in jwt.io or via debug logging and align configuration

Example fix

// before
quarkus.oidc.token.token-type=id_token
// after (service receives access tokens)
quarkus.oidc.token.token-type=access_token
Defensive patterns

Strategy: validation

Validate before calling

String typ = decodedJwt.getHeader("typ");
if (!expectedType.equals(typ)) throw new IllegalStateException("Send a token with typ=" + expectedType + ", got " + typ);

Type guard

boolean hasExpectedTyp(Map<String,Object> jwtHeader, String expected) { return expected.equals(jwtHeader.get("typ")); }

Try / catch

try { validate(token); } catch (OIDCException e) { throw new UnauthorizedException("Wrong token type: send the " + expectedTokenType); }

Prevention

When it happens

Trigger: Verifying a bearer token whose JWT header 'typ' (e.g. 'ID', 'Bearer', 'access') does not match the configured OidcTenantConfig tokenType; passing an ID token where an access token is required (or vice versa).

Common situations: Sending an ID token as a bearer token to a service expecting an access token; Keycloak/other IdP typ headers differing from expectations; explicitly configured quarkus.oidc.token.token-type that mismatches actual tokens.

Understand the failure class

Related errors


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