apereo/cas · error · IllegalArgumentException

Invalid sector identifier uri

Error message

Invalid sector identifier uri

What it means

When the registration request supplies a sector_identifier_uri, the translator fetches it and expects the document to be a JSON array of redirect URIs exactly equal to the request's redirect_uris. If the fetched list differs, translate() throws this IllegalArgumentException per the OIDC dynamic registration spec.

Solutions

  1. Update the sector_identifier_uri document so its JSON array exactly equals the redirect_uris sent in the registration request (same values, same order)
  2. If redirect URIs differ across clients, host a per-client sector identifier document or omit sector_identifier_uri
  3. Check for trailing-slash or http vs https differences between the document and request URIs

Example fix

// before (sector document)
["https://app.example.com/other-callback"]
// after (must match request redirect_uris)
["https://app.example.com/callback"]
Defensive patterns

Strategy: validation

Validate before calling

List<String> sectorUrls = fetchSectorIdentifierUri(sectorUri);
if (!sectorUrls.equals(request.getRedirectUris())) {
    throw new IllegalStateException("sector_identifier_uri document must equal redirect_uris");
}

Try / catch

try { translator.translate(request); } catch (IllegalArgumentException e) { if (e.getMessage().contains("sector identifier")) { /* reconcile sector document with redirect_uris */ } else throw e; }

Prevention

When it happens

Trigger: translate() -> validate(): a sector_identifier_uri is provided, the remote document returns HTTP 200 and parses as a JSON array of strings, but that array does not exactly match (order-sensitive) registrationRequest.getRedirectUris().

Common situations: The sector identifier document is shared across several clients with different redirect URI sets, the document is stale after the client changed redirect URIs, or list ordering differs between the document and the request.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/ac52f1a7c269006d. 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:276

    private void validate(final OidcClientRegistrationRequest registrationRequest,
                          final OidcRegisteredService registeredService) throws Exception {
        val context = configurationContext.getObject();
        if (StringUtils.isNotBlank(registeredService.getSectorIdentifierUri())) {
            HttpResponse sectorResponse = null;
            try {
                val exec = HttpExecutionRequest
                    .builder()
                    .method(HttpMethod.GET)
                    .url(registeredService.getSectorIdentifierUri())
                    .build();
                sectorResponse = HttpUtils.execute(exec);
                if (sectorResponse != null && sectorResponse.getCode() == HttpStatus.SC_OK) {
                    try (val content = ((HttpEntityContainer) sectorResponse).getEntity().getContent()) {
                        val result = IOUtils.toString(content, StandardCharsets.UTF_8);
                        val expectedType = MAPPER.getTypeFactory().constructParametricType(List.class, String.class);
                        val urls = MAPPER.readValue(JsonValue.readHjson(result).toString(), expectedType);
                        if (!urls.equals(registrationRequest.getRedirectUris())) {
                            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");

View on GitHub (pinned to e7288fc434)