{"record":{"id":"2e2b7e28043e4782","repo":"quarkusio/quarkus","slug":"invalid-token-type","errorCode":null,"errorMessage":"Invalid token type","messagePattern":"Invalid token type","errorType":"exception","errorClass":"io.quarkus.oidc.runtime.OIDCException","httpStatus":null,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java","lineNumber":496,"sourceCode":"\n    public static void setSecurityIdentityIntrospection(Builder builder, TokenIntrospection introspectionResult) {\n        if (introspectionResult != null) {\n            builder.addAttribute(INTROSPECTION_ATTRIBUTE, introspectionResult);\n        }\n    }\n\n    public static void setSecurityIdentityConfigMetadata(QuarkusSecurityIdentity.Builder builder,\n            TenantConfigContext resolvedContext) {\n        if (resolvedContext.provider().client != null) {\n            builder.addAttribute(CONFIG_METADATA_ATTRIBUTE, resolvedContext.provider().client.getMetadata());\n        }\n    }\n\n    public static void validatePrimaryJwtTokenType(Token tokenConfig, JsonObject tokenJson) {\n        if (tokenJson.containsKey(\"typ\")) {\n            String type = tokenJson.getString(\"typ\");\n            if (tokenConfig.tokenType().isPresent() && !tokenConfig.tokenType().get().equals(type)) {\n                throw new OIDCException(\"Invalid token type\");\n            } else if (\"Refresh\".equals(type)) {\n                // At least check it is not a refresh token issued by Keycloak\n                throw new OIDCException(\"Refresh token can only be used with the refresh token grant\");\n            }\n        }\n    }\n\n    static Uni<Void> removeSessionCookie(RoutingContext context, OidcTenantConfig oidcConfig,\n            TokenStateManager tokenStateManager) {\n        List<String> cookieNames = context.get(SESSION_COOKIE_NAME);\n        if (cookieNames != null) {\n            LOG.debugf(\"Remove session cookie names: %s\", cookieNames);\n            StringBuilder cookieValue = new StringBuilder();\n            for (String cookieName : cookieNames) {\n                cookieValue.append(removeCookie(context, oidcConfig, cookieName));\n            }\n            return tokenStateManager.deleteTokens(context, oidcConfig, cookieValue.toString(),\n                    deleteTokensRequestContext);","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java#L478-L514","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Set quarkus.oidc.token.token-type (or TokenConfig tokenType) to match the actual JWT 'typ' header, or remove the setting to skip this check","Send the correct token type (access token instead of ID token) in the Authorization header","Check the token's typ header in jwt.io or via debug logging and align configuration"],"exampleFix":"// before\nquarkus.oidc.token.token-type=id_token\n// after (service receives access tokens)\nquarkus.oidc.token.token-type=access_token","handlingStrategy":"validation","validationCode":"String typ = decodedJwt.getHeader(\"typ\");\nif (!expectedType.equals(typ)) throw new IllegalStateException(\"Send a token with typ=\" + expectedType + \", got \" + typ);","typeGuard":"boolean hasExpectedTyp(Map<String,Object> jwtHeader, String expected) { return expected.equals(jwtHeader.get(\"typ\")); }","tryCatchPattern":"try { validate(token); } catch (OIDCException e) { throw new UnauthorizedException(\"Wrong token type: send the \" + expectedTokenType); }","preventionTips":["Confirm the typ header of tokens your IdP issues","Match quarkus.oidc.token.token-type to the tokens actually sent","Never send ID tokens as bearer tokens to resource services"],"tags":["oidc","jwt","token-type","token-validation"],"backgroundTag":"invalid-type-token","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}