{"record":{"id":"9b6a41e65811e414","repo":"apereo/cas","slug":"invalid-policy-uri-from-an-unknown-host","errorCode":null,"errorMessage":"Invalid policy uri from an unknown host","messagePattern":"Invalid policy uri from an unknown host","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/dynareg/OidcDefaultClientRegistrationRequestTranslator.java","lineNumber":301,"sourceCode":"        }\n\n        val oidc = context.getCasProperties().getAuthn().getOidc();\n        if (!oidc.getRegistration().getDynamicClientRegistrationMode().isProtected()\n            && (StringUtils.isNotBlank(registrationRequest.getPolicyUri()) || StringUtils.isNotBlank(registrationRequest.getLogo()))) {\n            val hosts = registrationRequest.getRedirectUris()\n                .stream()\n                .map(uri -> FunctionUtils.doUnchecked(() -> new URI(uri).getHost())).toList();\n            if (StringUtils.isNotBlank(registrationRequest.getLogo())) {\n                val logo = new URI(registrationRequest.getLogo()).getHost();\n                if (!hosts.contains(logo)) {\n                    throw new IllegalArgumentException(\"Invalid logo uri from an unknown host\");\n                }\n            }\n\n            if (StringUtils.isNotBlank(registrationRequest.getPolicyUri())) {\n                val policy = new URI(registrationRequest.getPolicyUri()).getHost();\n                if (!hosts.contains(policy)) {\n                    throw new IllegalArgumentException(\"Invalid policy uri from an unknown host\");\n                }\n            }\n        }\n\n        if (Strings.CI.equalsAny(registeredService.getBackchannelTokenDeliveryMode(),\n            OidcBackchannelTokenDeliveryModes.PUSH.getMode(), OidcBackchannelTokenDeliveryModes.PING.getMode())) {\n            Assert.hasText(registeredService.getBackchannelClientNotificationEndpoint(),\n                \"Backchannel client notification endpoint must be specified\");\n            Assert.isTrue(Strings.CI.startsWith(registeredService.getBackchannelClientNotificationEndpoint(), \"https://\"),\n                \"Backchannel client notification endpoint MUST be an HTTPS url\");\n        }\n\n    }\n\n}\n","sourceCodeStart":283,"sourceCodeEnd":317,"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/OidcDefaultClientRegistrationRequestTranslator.java#L283-L317","documentation":"Like the logo check, the translator requires the policy_uri host to appear among the redirect URI hosts. A policy document served from any other host is rejected with this IllegalArgumentException during dynamic client registration.","triggerScenarios":"translate() -> validate(): registrationRequest.getPolicyUri() is non-blank and new URI(policyUri).getHost() is not in the hosts derived from redirect_uris.","commonSituations":"Pointing policy_uri at a separate corporate/legal site (e.g. policies.example.org) while the app lives on app.example.com; leaving a template or example policy URL in the registration request.","solutions":["Serve the policy document from the same host as one of the redirect URIs","Add the policy host to redirect_uris (only if genuinely a valid redirect target)","Omit policy_uri from the registration request and configure it later via service management"],"exampleFix":"// before\n\"redirect_uris\": [\"https://app.example.com/callback\"],\n\"policy_uri\": \"https://legal.example.org/privacy\"\n// after\n\"redirect_uris\": [\"https://app.example.com/callback\"],\n\"policy_uri\": \"https://app.example.com/privacy\"","handlingStrategy":"validation","validationCode":"Set<String> hosts = request.getRedirectUris().stream()\n    .map(u -> URI.create(u).getHost()).collect(Collectors.toSet());\nif (request.getPolicyUri() != null && !hosts.contains(URI.create(request.getPolicyUri()).getHost())) {\n    throw new IllegalArgumentException(\"policy_uri host must match a redirect_uri host\");\n}","typeGuard":null,"tryCatchPattern":"try { translator.translate(request); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"policy uri\")) { /* fix policy_uri host */ } else throw e; }","preventionTips":["Host policy documents on the application's own domain","Omit policy_uri when no same-host document exists","Check hosts of all client metadata URIs in one validation pass"],"tags":["oidc","dynamic-client-registration","validation","uri"],"backgroundTag":"invalid-url","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"}