apereo/cas · error · UnauthorizedProxyingException
UNAUTHORIZED_SERVICE_PROXY
UNAUTHORIZED_SERVICE_PROXY
Error message
Proxying is not allowed for registered service
What it means
When a TicketGrantingTicket was obtained by another service (proxiedBy), AbstractCentralAuthenticationService.evaluateProxiedServiceIfNeeded checks that proxying service's ProxyPolicy. If the policy disallows proxying, it throws UnauthorizedProxyingException (code UNAUTHORIZED_SERVICE_PROXY) naming the registered service id.
Solutions
- Update the registered service to allow proxying: set a proxy policy, e.g. new RegexMatchingRegisteredServiceProxyPolicy("^https://your-service/.*")
- Ensure the proxying (callback) URL itself is registered in the service registry
- If proxying is not needed, stop requesting PGT/PTs and use plain service tickets
- Set service proxyPolicy explicitly in the JSON/YAML service definition instead of relying on defaults
Example fix
// before (default: refuse)
"proxyPolicy": null
// after
{
"@class": "org.apereo.cas.services.RegexMatchingRegisteredServiceProxyPolicy",
"pattern": "^https://proxy-consumer\.example\.org/.*"
} Defensive patterns
Strategy: validation
Validate before calling
RegisteredService svc = servicesManager.findServiceBy(proxiedBy);
boolean mayProxy = svc != null && svc.getProxyPolicy() != null && svc.getProxyPolicy().isAllowedToProxy();
if (!mayProxy) throw new IllegalStateException("Enable proxy policy for " + proxiedBy); Try / catch
try {
centralAuthenticationService.grantProxyTicket(...);
} catch (UnauthorizedProxyingException e) {
logger.error("Proxying refused for service {}: {}", serviceId, e.getMessage());
} Prevention
- Set an allowing proxy policy on services that need PGTs
- Register the proxy callback (proxiedBy) URL in the service registry
- Audit service definitions after CAS upgrades — proxy defaults are strict
When it happens
Trigger: Requesting a proxy ticket or ST with a PGT where the pgtUrl's service (proxiedBy) is registered but its registeredService.getProxyPolicy().isAllowedToProxy() is false (e.g. default RefusePermissionToProxyPolicy).
Common situations: Service registered without proxy-granting policy enabled (org.apereo.cas.services.RegexMatchingRegisteredServiceProxyPolicy not set); service not registered at all; CAS 5+ stricter proxy policy enforcement breaking legacy PGT clients.
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
- Denied
- cannot be authorized
- Cannot authorize principal
- No metadata resolvers could be configured for service with…
- Interrupt response has blocked the authentication flow
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/9ef3b405b78b26ad.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core/src/main/java/org/apereo/cas/AbstractCentralAuthenticationService.java:82
} catch (final Throwable e) {
LoggingUtils.error(LOGGER, e);
}
throw new UnsatisfiedAuthenticationPolicyException(policy);
}
protected void evaluateProxiedServiceIfNeeded(@Nullable final Service service,
final TicketGrantingTicket ticketGrantingTicket,
@Nullable final RegisteredService registeredService) {
val proxiedBy = ticketGrantingTicket.getProxiedBy();
if (proxiedBy != null) {
LOGGER.debug("Ticket-granting ticket is proxied by [{}]. Locating proxy service in registry...", proxiedBy.getId());
val proxyingService = configurationContext.getServicesManager().findServiceBy(proxiedBy, CasModelRegisteredService.class);
if (proxyingService != null) {
LOGGER.debug("Located proxying service [{}] in the service registry", proxyingService);
if (!proxyingService.getProxyPolicy().isAllowedToProxy()) {
LOGGER.warn("Proxying service [{}] is not authorized to fulfill the proxy attempt made by [{}]",
proxyingService.getId(), Objects.requireNonNull(service).getId());
throw new UnauthorizedProxyingException(UnauthorizedProxyingException.MESSAGE + Objects.requireNonNull(registeredService).getId());
}
} else {
LOGGER.warn("Proxy attempt by service [{}] (registered service [{}]) is not allowed.",
Objects.requireNonNull(service).getId(), Objects.requireNonNull(registeredService).getId());
throw new UnauthorizedProxyingException(UnauthorizedProxyingException.MESSAGE + registeredService.getId());
}
} else {
LOGGER.trace("Ticket-granting ticket is not proxied by another service");
}
}
protected @Nullable Service resolveServiceFromAuthenticationRequest(final Service service) throws Throwable {
return configurationContext.getAuthenticationServiceSelectionPlan().resolveService(service, Service.class);
}
protected boolean isTicketAuthenticityVerified(final String ticketId) {
try {
if (configurationContext.getCipherExecutor() != null) {View on GitHub (pinned to e7288fc434)