apereo/cas · error · IllegalArgumentException

Invalid policy uri from an unknown host

Error message

Invalid policy uri from an unknown host

What it means

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.

Solutions

  1. Serve the policy document from the same host as one of the redirect URIs
  2. Add the policy host to redirect_uris (only if genuinely a valid redirect target)
  3. Omit policy_uri from the registration request and configure it later via service management

Example fix

// before
"redirect_uris": ["https://app.example.com/callback"],
"policy_uri": "https://legal.example.org/privacy"
// after
"redirect_uris": ["https://app.example.com/callback"],
"policy_uri": "https://app.example.com/privacy"
Defensive patterns

Strategy: validation

Validate before calling

Set<String> hosts = request.getRedirectUris().stream()
    .map(u -> URI.create(u).getHost()).collect(Collectors.toSet());
if (request.getPolicyUri() != null && !hosts.contains(URI.create(request.getPolicyUri()).getHost())) {
    throw new IllegalArgumentException("policy_uri host must match a redirect_uri host");
}

Try / catch

try { translator.translate(request); } catch (IllegalArgumentException e) { if (e.getMessage().contains("policy uri")) { /* fix policy_uri host */ } else throw e; }

Prevention

When it happens

Trigger: translate() -> validate(): registrationRequest.getPolicyUri() is non-blank and new URI(policyUri).getHost() is not in the hosts derived from redirect_uris.

Common situations: 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.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/9b6a41e65811e414. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/dynareg/OidcDefaultClientRegistrationRequestTranslator.java:301

        }

        val oidc = context.getCasProperties().getAuthn().getOidc();
        if (!oidc.getRegistration().getDynamicClientRegistrationMode().isProtected()
            && (StringUtils.isNotBlank(registrationRequest.getPolicyUri()) || StringUtils.isNotBlank(registrationRequest.getLogo()))) {
            val hosts = registrationRequest.getRedirectUris()
                .stream()
                .map(uri -> FunctionUtils.doUnchecked(() -> new URI(uri).getHost())).toList();
            if (StringUtils.isNotBlank(registrationRequest.getLogo())) {
                val logo = new URI(registrationRequest.getLogo()).getHost();
                if (!hosts.contains(logo)) {
                    throw new IllegalArgumentException("Invalid logo uri from an unknown host");
                }
            }

            if (StringUtils.isNotBlank(registrationRequest.getPolicyUri())) {
                val policy = new URI(registrationRequest.getPolicyUri()).getHost();
                if (!hosts.contains(policy)) {
                    throw new IllegalArgumentException("Invalid policy uri from an unknown host");
                }
            }
        }

        if (Strings.CI.equalsAny(registeredService.getBackchannelTokenDeliveryMode(),
            OidcBackchannelTokenDeliveryModes.PUSH.getMode(), OidcBackchannelTokenDeliveryModes.PING.getMode())) {
            Assert.hasText(registeredService.getBackchannelClientNotificationEndpoint(),
                "Backchannel client notification endpoint must be specified");
            Assert.isTrue(Strings.CI.startsWith(registeredService.getBackchannelClientNotificationEndpoint(), "https://"),
                "Backchannel client notification endpoint MUST be an HTTPS url");
        }

    }

}

View on GitHub (pinned to e7288fc434)