{"record":{"id":"a543f310777fdb11","repo":"quarkusio/quarkus","slug":"application-web-app-type-is-only-supported-if-ac","errorCode":null,"errorMessage":"Application 'web-app' type is only supported if access token is the source of roles","messagePattern":"Application 'web-app' type is only supported if access token is the source of roles","errorType":"exception","errorClass":"OIDCException","httpStatus":null,"severity":"error","filePath":"extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java","lineNumber":41,"sourceCode":"import io.quarkus.proxy.ProxyConfiguration;\nimport io.quarkus.proxy.ProxyConfigurationRegistry;\nimport io.quarkus.runtime.configuration.ConfigurationException;\n\npublic final class KeycloakPolicyEnforcerUtil {\n\n    private KeycloakPolicyEnforcerUtil() {\n        // UTIL CLASS\n    }\n\n    static PolicyEnforcer createPolicyEnforcer(OidcTenantConfig oidcConfig,\n            KeycloakPolicyEnforcerTenantConfig keycloakPolicyEnforcerConfig,\n            TlsConfigSupport tlsConfigSupport,\n            ProxyConfigurationRegistry proxyConfigurationRegistry) {\n\n        if (oidcConfig.applicationType()\n                .orElse(OidcTenantConfig.ApplicationType.SERVICE) == OidcTenantConfig.ApplicationType.WEB_APP\n                && oidcConfig.roles().source().orElse(null) != OidcTenantConfig.Roles.Source.accesstoken) {\n            throw new OIDCException(\"Application 'web-app' type is only supported if access token is the source of roles\");\n        }\n\n        AdapterConfig adapterConfig = new AdapterConfig();\n        String authServerUrl = oidcConfig.authServerUrl().get();\n\n        try {\n            adapterConfig.setRealm(authServerUrl.substring(authServerUrl.lastIndexOf('/') + 1));\n            adapterConfig.setAuthServerUrl(authServerUrl.substring(0, authServerUrl.lastIndexOf(\"/realms\")));\n        } catch (Exception cause) {\n            throw new ConfigurationException(\"Failed to parse the realm name.\", cause);\n        }\n\n        adapterConfig.setResource(oidcConfig.clientId().get());\n        adapterConfig.setCredentials(getCredentials(oidcConfig));\n\n        if (!tlsConfigSupport.useTlsRegistry()) {\n            if (tlsConfigSupport.isGlobalTrustAll()) {\n                adapterConfig.setDisableTrustManager(true);","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerUtil.java#L23-L59","documentation":"KeycloakPolicyEnforcerUtil.createPolicyEnforcer rejects OidcTenantConfig whose applicationType is web-app unless the role source is the access token. The policy enforcer relies on claims from the access token to make authorization decisions, so role sources like idtoken or userinfo are incompatible with web-app type.","triggerScenarios":"Configuring quarkus.oidc.application-type=web-app (or leaving tenant config resolving to WEB_APP) together with quarkus.oidc.roles.source=user-id-token or =userinfo (or any source other than accesstoken) while the policy enforcer is enabled.","commonSituations":"Copying OIDC web-app role config (roles.source=userinfo) into an application that also enables quarkus.keycloak.policy-enforcer.enabled=true; switching an app from service to web-app type without revisiting role source.","solutions":["Set quarkus.oidc.roles.source=accesstoken so roles come from the access token.","Or change quarkus.oidc.application-type=service if the app does not need web-app behavior.","Remove conflicting roles.source configuration (leave default) when using the policy enforcer with web-app type."],"exampleFix":"// before\nquarkus.oidc.application-type=web-app\nquarkus.oidc.roles.source=userinfo\n// after\nquarkus.oidc.application-type=web-app\nquarkus.oidc.roles.source=accesstoken","handlingStrategy":"validation","validationCode":"// fail fast at startup if config is incompatible\nOidcTenantConfig c = /* resolved tenant config */;\nboolean webApp = c.applicationType().orElse(OidcTenantConfig.ApplicationType.SERVICE)\n        == OidcTenantConfig.ApplicationType.WEB_APP;\nboolean badSource = c.roles().source().isPresent()\n        && c.roles().source().get() != OidcTenantConfig.Roles.Source.accesstoken;\nif (webApp && badSource) throw new IllegalStateException(\"Set roles.source=accesstoken for web-app + policy enforcer\");","typeGuard":null,"tryCatchPattern":"try {\n    policyEnforcer = KeycloakPolicyEnforcerUtil.createPolicyEnforcer(...);\n} catch (OIDCException e) {\n    if (e.getMessage().contains(\"access token is the source of roles\")) {\n        log.error(\"Set quarkus.oidc.roles.source=accesstoken or application-type=service\");\n    }\n    throw e;\n}","preventionTips":["When enabling the policy enforcer, audit quarkus.oidc.roles.source settings.","Do not copy web-app role-source config (userinfo/idtoken) into policy-enforcer apps.","Document that web-app + policy enforcer requires access-token roles."],"tags":["oidc","keycloak","configuration","policy-enforcer"],"backgroundTag":"incompatible-oidc-role-source","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"}