apereo/cas · error · UnauthorizedServiceException

Realm [ ] is not authorized for matching service [ ]

Error message

Realm [{}] is not authorized for matching service [{}]

What it means

The wtrealm value presented in the WS-Federation request is blank or does not (case-insensitively) match the realm configured on the matching WSFederationRegisteredService, so the request is rejected with UnauthorizedServiceException.denied().

Solutions

  1. Set the registered service's realm to exactly the wtrealm the application sends (or fix the app's wtrealm)
  2. Compare the logged realm and service values for whitespace/scheme/path differences and correct them
  3. Verify service matching resolves the intended WSFederationRegisteredService (serviceId pattern not too greedy)
  4. Re-test with a fresh sign-in request after fixing the realm

Example fix

// before
"realm": "https://app.example.com/"  (app sends https://app.example.com)
// after
"realm": "https://app.example.com"
Defensive patterns

Strategy: validation

Validate before calling

if (fedRequest.wtrealm() == null || !fedRequest.wtrealm().equalsIgnoreCase(registeredService.getRealm())) {
    throw new IllegalArgumentException("wtrealm does not match registered service realm");
}

Try / catch

try { controller.findAndValidateFederationRequestForRegisteredService(service, request); }
catch (UnauthorizedServiceException e) { /* inspect realm config of app and CAS service */ }

Prevention

When it happens

Trigger: findAndValidateFederationRequestForRegisteredService() compares fedRequest.wtrealm() against svc.getRealm() via Strings.CI.equals and fails, then throws UnauthorizedServiceException.

Common situations: Application's wtrealm/Realm query parameter differs from the realm set on the CAS registered service (trailing slash, http vs https host, case handled only loosely); service resolution matched a different/wrong registered service; app upgraded and changed its realm identifier.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-ws-idp/src/main/java/org/apereo/cas/ws/idp/web/BaseWSFederationRequestController.java:130

            return true;
        }

        val ttlMs = TimeUnit.MINUTES.toMillis(ttl);
        if (ttlMs > 0) {
            val createdDate = idpToken.getCreated();
            if (createdDate != null) {
                val expiryDate = new Date(createdDate.toEpochMilli() + ttlMs);
                return expiryDate.before(new Date());
            }
        }
        return false;
    }

    protected WSFederationRegisteredService findAndValidateFederationRequestForRegisteredService(final Service targetService,
                                                                                                 final WSFederationRequest fedRequest) {
        val svc = getWsFederationRegisteredService(targetService);
        if (StringUtils.isBlank(fedRequest.wtrealm()) || !Strings.CI.equals(fedRequest.wtrealm(), svc.getRealm())) {
            LOGGER.warn("Realm [{}] is not authorized for matching service [{}]", fedRequest.wtrealm(), svc);
            throw UnauthorizedServiceException.denied("Rejected: %s".formatted(svc.getRealm()));
        }
        val idp = configContext.getCasProperties().getAuthn().getWsfedIdp().getIdp();
        if (!Strings.CI.equals(idp.getRealm(), svc.getRealm())) {
            LOGGER.warn("Realm [{}] is not authorized for the identity provider realm [{}]", fedRequest.wtrealm(), idp.getRealm());
            throw UnauthorizedServiceException.denied("Rejected: %s".formatted(svc.getRealm()));
        }

        return svc;
    }

    protected WSFederationRegisteredService getWsFederationRegisteredService(final Service targetService) {
        val svc = configContext.getServicesManager().findServiceBy(targetService, WSFederationRegisteredService.class);
        RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(targetService, svc);
        return svc;
    }

    /**

View on GitHub (pinned to e7288fc434)