{"record":{"id":"e6a3014409e41f6a","repo":"quarkusio/quarkus","slug":"introspection-path-is-configured-and-verifyaccess","errorCode":null,"errorMessage":"Introspection path is configured and 'verifyAccessTokenWithUserInfo' is enabled, these options are mutually exclusive","messagePattern":"Introspection path is configured and 'verifyAccessTokenWithUserInfo' is enabled, these options are mutually exclusive","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantContextFactory.java","lineNumber":340,"sourceCode":"                    || oidcConfig.roles().source()\n                            .orElse(null) == io.quarkus.oidc.runtime.OidcTenantConfig.Roles.Source.userinfo) {\n                throw new ConfigurationException(\n                        \"UserInfo is required but DefaultTokenStateManager is configured to not keep the access token\");\n            }\n            if (oidcConfig.roles().source().orElse(null) == io.quarkus.oidc.runtime.OidcTenantConfig.Roles.Source.accesstoken) {\n                throw new ConfigurationException(\n                        \"Access token is required to check the roles but DefaultTokenStateManager is configured to not keep the access token\");\n            }\n        }\n\n        if (oidcConfig.token().verifyAccessTokenWithUserInfo().orElse(false)) {\n            if (!oidcConfig.discoveryEnabled().orElse(true)) {\n                if (oidcConfig.userInfoPath().isEmpty()) {\n                    throw new ConfigurationException(\n                            \"UserInfo path is missing but 'verifyAccessTokenWithUserInfo' is enabled\");\n                }\n                if (oidcConfig.introspectionPath().isPresent()) {\n                    throw new ConfigurationException(\n                            \"Introspection path is configured and 'verifyAccessTokenWithUserInfo' is enabled, these options are mutually exclusive\");\n                }\n            }\n        }\n\n        if (!oidcConfig.token().issuedAtRequired() && oidcConfig.token().age().isPresent()) {\n            String tokenIssuedAtRequired = getConfigPropertyForTenant(tenantId, \"token.issued-at-required\");\n            String tokenAge = getConfigPropertyForTenant(tenantId, \"token.age\");\n            throw new ConfigurationException(\n                    \"The '\" + tokenIssuedAtRequired + \"' can only be set to false if '\" + tokenAge + \"' is not set.\" +\n                            \" Either set '\" + tokenIssuedAtRequired + \"' to true or do not set '\" + tokenAge + \"'.\",\n                    Set.of(tokenIssuedAtRequired, tokenAge));\n        }\n\n        return createOidcProvider(oidcConfig).flatMap(p -> TenantConfigContext.createReady(p, oidcConfig));\n    }\n\n    private void verifyAllowedRoutes(OidcTenantConfig oidcConfig, String tenantId) {","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantContextFactory.java#L322-L358","documentation":"Verifying the access token via UserInfo and via token introspection are two alternative verification mechanisms; configuring both is contradictory. When discovery is disabled and both introspectionPath and verifyAccessTokenWithUserInfo are set, Quarkus rejects the tenant configuration.","triggerScenarios":"verifyAccessTokenWithUserInfo() is true, discoveryEnabled() is false, and introspectionPath().isPresent() at createTenantContext.","commonSituations":"Configuring both quarkus.oidc.introspection-path and quarkus.oidc.user-info-path with verify-access-token-with-user-info=true on a discovery-disabled tenant; switching verification methods without removing the old path property.","solutions":["Remove quarkus.oidc.introspection-path if UserInfo verification is desired","Set token.verify-access-token-with-user-info=false to use introspection instead","Re-enable discovery and configure verification strategy explicitly via token.allow-opaque-token-introspection/verification preferences"],"exampleFix":"// before\nquarkus.oidc.discovery-enabled=false\nquarkus.oidc.introspection-path=/introspect\nquarkus.oidc.token.verify-access-token-with-user-info=true\n// after\nquarkus.oidc.discovery-enabled=false\nquarkus.oidc.token.verify-access-token-with-user-info=true\nquarkus.oidc.user-info-path=/userinfo\n# introspection-path removed","handlingStrategy":"validation","validationCode":"if (config.token().verifyAccessTokenWithUserInfo().orElse(false) && config.introspectionPath().isPresent()) {\n    throw new IllegalArgumentException(\"choose either UserInfo or introspection, not both\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Decide one access-token verification mechanism per tenant","Remove legacy introspection-path when enabling verify-access-token-with-user-info"],"tags":["quarkus","oidc","configuration","introspection"],"backgroundTag":"oidc-mutually-exclusive-verification-options","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"}