apereo/cas · error · IllegalArgumentException

Invalid logo uri from an unknown host

Error message

Invalid logo uri from an unknown host

What it means

The translator restricts the client's logo_uri to hosts already present in the request's redirect URIs, preventing a client from pointing its logo at an arbitrary host. If the logo URI's host is not among the redirect URI hosts, translate() -> validate() throws this IllegalArgumentException.

Solutions

  1. Host the logo on the same host as one of the redirect URis, or add that host to the redirect_uris
  2. Register the client without a logo and attach it via service management afterward if allowed
  3. Normalize the logo URI (correct scheme/host) so its host matches a redirect URI host

Example fix

// before
"redirect_uris": ["https://app.example.com/callback"],
"logo_uri": "https://cdn.example.net/logo.png"
// after
"redirect_uris": ["https://app.example.com/callback"],
"logo_uri": "https://app.example.com/logo.png"
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

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

Prevention

When it happens

Trigger: translate() -> validate(): registrationRequest.getLogo() is non-blank and new URI(logo).getHost() is not contained in the set of hosts extracted from redirect_uris.

Common situations: Hosting the logo on a CDN (e.g. cdn.example.com) while redirect URIs point at app.example.com; using a placeholder or external image URL like a logo from a public icon service; protocol-relative or typo'd hosts.

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/d9884253f80e2c8c. 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:294

                            throw new IllegalArgumentException("Invalid sector identifier uri");
                        }
                    }
                }
            } finally {
                HttpUtils.close(sectorResponse);
            }
        }

        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)