{"record":{"id":"150b5f52718f4581","repo":"quarkusio/quarkus","slug":"userinfo-is-required-but-defaulttokenstatemanager","errorCode":null,"errorMessage":"UserInfo is required but DefaultTokenStateManager is configured to not keep the access token","messagePattern":"UserInfo is required but DefaultTokenStateManager is configured to not keep the access token","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantContextFactory.java","lineNumber":324,"sourceCode":"                        \"Session age extension will not be effective because 'quarkus.oidc.token.refresh-expired=true' is not set\");\n            }\n            if (!oidcConfig.token().refreshExpired()\n                    && !oidcConfig.token().refreshTokenCacheTimeToLive().isZero()) {\n                throw new ConfigurationException(\n                        \"'\" + getConfigPropertyForTenant(tenantId, \"token.refresh-expired\")\n                                + \"' must be enabled to use '\"\n                                + getConfigPropertyForTenant(tenantId, \"token.refresh-token-cache-time-to-live\")\n                                + \"'\");\n            }\n        }\n\n        if (oidcConfig.tokenStateManager()\n                .strategy() != io.quarkus.oidc.runtime.OidcTenantConfig.TokenStateManager.Strategy.KEEP_ALL_TOKENS) {\n\n            if (oidcConfig.authentication().userInfoRequired().orElse(false)\n                    || 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                }","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantContextFactory.java#L306-L342","documentation":"The DefaultTokenStateManager stores tokens in the encrypted session cookie; with the default strategy it does not keep the access token. If UserInfo is required (or roles come from userinfo) the access token is needed to call the UserInfo endpoint, so Quarkus fails the tenant context with this ConfigurationException.","triggerScenarios":"tokenStateManager().strategy() != KEEP_ALL_TOKENS while authentication().userInfoRequired()=true or roles().source()==userinfo, at createTenantContext time.","commonSituations":"Customizing quarkus.oidc.token-state-manager.strategy (e.g. keep-id-token or state-only) while still requiring UserInfo or userinfo-based roles; tightening the cookie size by dropping the access token then hitting UserInfo requirements.","solutions":["Set quarkus.oidc.token-state-manager.strategy=keep-all-tokens so the access token is retained","Remove the requirement: set authentication.user-info-required=false and roles.source away from userinfo","Use a custom TokenStateManager if session-cookie size is the concern, while still persisting the access token"],"exampleFix":"// before\nquarkus.oidc.authentication.user-info-required=true\nquarkus.oidc.token-state-manager.strategy=keep-id-token\n// after\nquarkus.oidc.authentication.user-info-required=true\nquarkus.oidc.token-state-manager.strategy=keep-all-tokens","handlingStrategy":"validation","validationCode":"boolean keepsAccessToken = config.tokenStateManager().strategy() == TokenStateManager.Strategy.KEEP_ALL_TOKENS;\nif (!keepsAccessToken && (config.authentication().userInfoRequired().orElse(false)\n        || config.roles().source().orElse(null) == Roles.Source.userinfo)) {\n    throw new IllegalArgumentException(\"strategy must be keep-all-tokens when UserInfo is required\");\n}","typeGuard":"boolean keepsAccessToken(OidcTenantConfig c) {\n    return c.tokenStateManager().strategy() == OidcTenantConfig.TokenStateManager.Strategy.KEEP_ALL_TOKENS;\n}","tryCatchPattern":null,"preventionTips":["Treat token-state-manager.strategy changes as breaking UserInfo features","Prefer keep-all-tokens unless cookie size is a proven problem","Test UserInfo flows after changing strategy"],"tags":["quarkus","oidc","configuration","userinfo"],"backgroundTag":"oidc-token-state-strategy-conflict","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"}