{"record":{"id":"72aeb5b6d6a6b9e9","repo":"quarkusio/quarkus","slug":"token-is-opaque-but-the-opaque-token-introspection","errorCode":null,"errorMessage":"Token is opaque but the opaque token introspection is not allowed","messagePattern":"Token is opaque but the opaque token introspection is not allowed","errorType":"exception","errorClass":"AuthenticationFailedException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java","lineNumber":670,"sourceCode":"                    TokenType.CODE_FLOW_ACCESS_TOKEN, false, userInfo);\n        } else {\n            return NULL_CODE_ACCESS_TOKEN_UNI;\n        }\n    }\n\n    private Uni<TokenVerificationResult> verifyTokenUni(Map<String, Object> requestData, TenantConfigContext resolvedContext,\n            TokenCredential tokenCred, TokenType tokenType, boolean enforceAudienceVerification,\n            UserInfo userInfo) {\n        final String token = tokenCred.getToken();\n        Long expiresIn = null;\n        if (tokenType == TokenType.CODE_FLOW_ACCESS_TOKEN) {\n            expiresIn = ((AuthorizationCodeTokens) requestData.get(AuthorizationCodeTokens.class.getName()))\n                    .getAccessTokenExpiresIn();\n        }\n        if (OidcUtils.isOpaqueToken(token)) {\n            if (!resolvedContext.oidcConfig().token().allowOpaqueTokenIntrospection()) {\n                LOG.debug(\"Token is opaque but the opaque token introspection is not allowed\");\n                throw new AuthenticationFailedException(tokenMap(tokenCred));\n            }\n            // verify opaque access token with UserInfo if enabled and introspection URI is absent\n            if (resolvedContext.oidcConfig().token().verifyAccessTokenWithUserInfo().orElse(false)\n                    && resolvedContext.provider().getMetadata().getIntrospectionUri() == null) {\n                if (userInfo == null) {\n                    return Uni.createFrom().failure(\n                            new AuthenticationFailedException(\"Opaque access token verification failed as user info is null.\",\n                                    tokenMap(tokenCred)));\n                } else {\n                    // valid token verification result\n                    return Uni.createFrom().item(new TokenVerificationResult(null, null));\n                }\n            }\n            LOG.debug(\"Starting the opaque token introspection\");\n            return introspectTokenUni(resolvedContext, token, tokenType, expiresIn, false);\n        } else if (resolvedContext.provider().getMetadata().getJsonWebKeySetUri() == null\n                || resolvedContext.oidcConfig().token().requireJwtIntrospectionOnly()) {\n            // Verify JWT token with the remote introspection","sourceCodeStart":652,"sourceCodeEnd":688,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java#L652-L688","documentation":"When the bearer token has no dot-separated JWT structure (opaque token), Quarkus must introspect it via the OIDC provider. This AuthenticationFailedException is thrown when the token is opaque but 'quarkus.oidc.token.allow-opaque-token-introspection' is false (the default), so introspection is refused outright.","triggerScenarios":"quarkus.oidc.token.allow-opaque-token-introspection=false (default) while the token issued by the provider is an opaque (non-JWT) access token, verified via verifyTokenUni or verifyCodeFlowAccessTokenUni.","commonSituations":"Keycloak or another IdP configured to issue reference (opaque) tokens while the Quarkus app assumes JWTs; switching IdP or client profile from JWT to opaque tokens without updating Quarkus config.","solutions":["Set quarkus.oidc.token.allow-opaque-token-introspection=true.","Ensure the provider's introspection endpoint is discoverable/known (well-known metadata) so introspection can run.","Reconfigure the IdP client to issue JWT access tokens if local verification is preferred.","If the token should be a JWT, check that you are validating the access token, not an opaque reference token."],"exampleFix":"// application.properties\n// before\nquarkus.oidc.token.allow-opaque-token-introspection=false\n// after\nquarkus.oidc.token.allow-opaque-token-introspection=true","handlingStrategy":"validation","validationCode":"// application.properties check before startup\nif (tokenLooksOpaque(token) && !config.allowOpaqueTokenIntrospection()) {\n    throw new IllegalStateException(\"Enable quarkus.oidc.token.allow-opaque-token-introspection\");\n}","typeGuard":"boolean isJwtToken(String token) {\n    return token != null && token.chars().filter(c -> c == '.').count() == 2;\n}","tryCatchPattern":"try {\n    return authenticate(token);\n} catch (AuthenticationFailedException e) {\n    // fall back to a JWT-only flow or surface a config error\n}","preventionTips":["Confirm your IdP client's access-token format (JWT vs opaque/reference) before writing Quarkus config","Set allow-opaque-token-introspection=true whenever the provider may issue reference tokens","Ensure the introspection endpoint is available in the provider's discovery metadata"],"tags":["oidc","opaque-token","introspection","configuration"],"backgroundTag":"opaque-token-introspection-not-allowed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}