{"record":{"id":"331d860a252173cd","repo":"apereo/cas","slug":"dynamic-client-registration-mode-is-not-configured","errorCode":null,"errorMessage":"Dynamic client registration mode is not configured as protected.","messagePattern":"Dynamic client registration mode is not configured as protected\\.","errorType":"console","errorClass":null,"httpStatus":406,"severity":"warning","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/dynareg/OidcInitialAccessTokenController.java","lineNumber":101,"sourceCode":"    @GetMapping(value = {\n        '/' + OidcConstants.BASE_OIDC_URL + '/' + OidcConstants.REGISTRATION_INITIAL_TOKEN_URL,\n        \"/**/\" + OidcConstants.REGISTRATION_INITIAL_TOKEN_URL\n    }, produces = MediaType.APPLICATION_JSON_VALUE)\n    @Operation(summary = \"Handle OIDC initial access token request\")\n    public ModelAndView handleRequestInternal(\n        final HttpServletRequest request, final HttpServletResponse response) {   \n        val webContext = new JEEContext(request, response);\n        if (!getConfigurationContext().getIssuerService().validateIssuer(webContext, List.of(OidcConstants.REGISTRATION_INITIAL_TOKEN_URL))) {\n            val body = OAuth20Utils.getErrorResponseBody(OAuth20Constants.INVALID_REQUEST, \"Invalid issuer\");\n            val modelAndView = new ModelAndView(new JacksonJsonView(), body);\n            modelAndView.setStatus(HttpStatus.BAD_REQUEST);\n            return modelAndView;\n        }\n        val casProperties = getConfigurationContext().getCasProperties();\n        val oidcProperties = casProperties.getAuthn().getOidc();\n\n        if (!oidcProperties.getRegistration().getDynamicClientRegistrationMode().isProtected()) {\n            LOGGER.warn(\"Dynamic client registration mode is not configured as protected.\");\n            return getBadRequestResponseEntity(HttpStatus.NOT_ACCEPTABLE);\n        }\n        val callContext = new CallContext(webContext, getConfigurationContext().getSessionStore(),\n            getConfigurationContext().getOauthConfig().getProfileManagerFactory());\n        return accessTokenClient.getCredentials(callContext)\n            .map(credentials -> accessTokenClient.validateCredentials(callContext, credentials))\n            .filter(Optional::isPresent)\n            .map(Optional::get)\n            .map(credentials -> {\n                val principal = FunctionUtils.doUnchecked(() -> PrincipalFactoryUtils.newPrincipalFactory().createPrincipal(credentials.getUserProfile().getId()));\n                val service = getConfigurationContext().getWebApplicationServiceServiceFactory()\n                    .createService(casProperties.getServer().getPrefix());\n\n                val tokenRequestContext = AccessTokenRequestContext\n                    .builder()\n                    .authentication(DefaultAuthenticationBuilder.newInstance().setPrincipal(principal).build())\n                    .service(service)\n                    .grantType(OAuth20GrantTypes.NONE)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/dynareg/OidcInitialAccessTokenController.java#L83-L119","documentation":"CAS's dynamic client registration endpoint can be protected by an initial access token. This controller (initial-access-token mode) first checks that cas.authn.oidc.registration.dynamic-client-registration-mode is 'PROTECTED'; if it is ANY or omitted, it refuses the operation with HTTP 406 NOT_ACCEPTABLE because initial access tokens are meaningless in unprotected modes.","triggerScenarios":"POST to the OIDC registration endpoint while the initial-access-token controller is active and dynamicClientRegistrationMode is not PROTECTED (e.g. mode left unset, set to ANY).","commonSituations":"Deployers forgetting to set dynamic-client-registration-mode=PROTECTED after enabling registration; copying example configs with mode=ANY; upgrading CAS where default mode changed; hitting the wrong registration controller variant for the configured mode.","solutions":["Set cas.authn.oidc.registration.dynamic-client-registration-mode=PROTECTED","Obtain and supply a valid initial access token with the registration request","If open registration is intended, use the endpoint/mode matching ANY and do not require an initial token","Confirm the registered-mode flow via discovery metadata (registration_endpoint)"],"exampleFix":"// before\ncas.authn.oidc.registration.dynamic-client-registration-mode=ANY\n// after\ncas.authn.oidc.registration.dynamic-client-registration-mode=PROTECTED","handlingStrategy":"validation","validationCode":"if (registrationMode !== 'PROTECTED') {\n  throw new Error('Initial access token registration requires dynamic-client-registration-mode=PROTECTED');\n}\nif (!initialAccessToken) throw new Error('Missing initial access token for protected registration');","typeGuard":"function supportsInitialAccessToken(cfg) {\n  return cfg?.authn?.oidc?.registration?.dynamicClientRegistrationMode === 'PROTECTED';\n}","tryCatchPattern":"try {\n  return await registerClient(token);\n} catch (e) {\n  if (e.status === 406) {\n    // set mode to PROTECTED or use the open registration flow\n  }\n  throw e;\n}","preventionTips":["Set dynamic-client-registration-mode=PROTECTED before using initial access tokens","Provision the initial access token through CAS tooling","Match the endpoint variant to the configured mode","Re-check registration config after CAS upgrades"],"tags":["oidc","dynamic-client-registration","configuration","access-token"],"backgroundTag":"invalid-config-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}