apereo/cas · error
INVALID_PROXY_CALLBACK
INVALID_PROXY_CALLBACK
Error message
Failed to authenticate service credential [{}] What it means
During proxy ticket validation, CAS extracted a service credential (e.g. a PGT callback's proxy credentials) from the request but failed to authenticate it, so handleTicketValidation catches AuthenticationException and returns an INVALID_PROXY_CALLBACK error view. The proxy callback chain could not be completed.
Solutions
- Verify the pgtUrl/proxy callback endpoint is reachable over HTTPS and presents valid credentials; test the callback URL manually.
- Check the CAS log for the underlying AuthenticationException detail to identify which authentication handler rejected the service credential.
- Remove the pgtUrl parameter if proxy authentication is not actually needed, so no service credential is extracted and authenticated.
Example fix
// before GET /p3/proxyValidate?ticket=PT-1-abc&pgtUrl=https://myapp.example.org/callback-bad // after (valid, reachable callback or none) GET /p3/proxyValidate?ticket=PT-1-abc&pgtUrl=https://myapp.example.org/pgtCallback
Defensive patterns
Strategy: try-catch
Validate before calling
// before requesting proxy tickets, verify pgtUrl is reachable and TLS-valid
const resp = await fetch(pgtUrl, { method: 'HEAD' });
if (!resp.ok) throw new Error('pgtUrl callback is not reachable: ' + pgtUrl); Try / catch
try {
proxyGrantingTicket = handleProxyGrantingTicketDelivery(serviceTicketId, credential);
} catch (AuthenticationException e) {
// INVALID_PROXY_CALLBACK: fix/verify pgtUrl credentials and reachability
} Prevention
- Use HTTPS pgtUrls with valid certificates that CAS trusts.
- Test the proxy callback endpoint independently before wiring it into ticket validation.
- Omit pgtUrl when proxy authentication is not required.
When it happens
Trigger: handleTicketValidation calls getServiceCredentialsFromRequest (with pgtUrl callback processing enabled), gets a non-null credential, then handleProxyGrantingTicketDelivery authenticates it; the thrown AuthenticationException triggers the warn and the INVALID_PROXY_CALLBACK error response.
Common situations: pgtUrl points to an endpoint whose client certificate/credentials fail authentication; custom credential-to-handler setup mismatched; proxy callback URL unreachable or returning unexpected content causing the auth flow to fail.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Service [ ] is not found in service registry.
- INVALID_REQUEST
- Service ticket [ ] does not satisfy validation…
- Resolved credentials for this transaction are empty
- cannot be authorized
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/3017e2076ff94dee.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-validation-core/src/main/java/org/apereo/cas/web/AbstractServiceValidateController.java:170
protected void initBinder(final HttpServletRequest request, final ServletRequestDataBinder binder) {
if (serviceValidateConfigurationContext.getCasProperties().getSso().isRenewAuthnEnabled()) {
binder.setRequiredFields(CasProtocolConstants.PARAMETER_RENEW);
}
}
protected void prepareForTicketValidation(final HttpServletRequest request, final WebApplicationService service, final String serviceTicketId) {
}
protected ModelAndView handleTicketValidation(final HttpServletRequest request,
final HttpServletResponse response,
final WebApplicationService service, final String serviceTicketId) throws Throwable {
var proxyGrantingTicket = (Ticket) null;
val serviceCredential = getServiceCredentialsFromRequest(service, request);
if (serviceCredential != null) {
try {
proxyGrantingTicket = handleProxyGrantingTicketDelivery(serviceTicketId, serviceCredential);
} catch (final AuthenticationException e) {
LOGGER.warn("Failed to authenticate service credential [{}]", serviceCredential);
val description = getTicketValidationErrorDescription(CasProtocolConstants.ERROR_CODE_INVALID_PROXY_CALLBACK,
new Object[]{serviceCredential.getId()}, request);
return generateErrorView(CasProtocolConstants.ERROR_CODE_INVALID_PROXY_CALLBACK, description, request, service);
} catch (final InvalidTicketException e) {
LOGGER.error("Failed to create proxy granting ticket due to an invalid ticket for [{}]", serviceCredential);
LoggingUtils.error(LOGGER, e);
val description = getTicketValidationErrorDescription(e.getCode(), new Object[]{serviceTicketId}, request);
return generateErrorView(e.getCode(), description, request, service);
} catch (final AbstractTicketException e) {
LOGGER.error("Failed to create proxy granting ticket for [{}]", serviceCredential);
LoggingUtils.error(LOGGER, e);
val description = getTicketValidationErrorDescription(e.getCode(), new Object[]{serviceCredential.getId()}, request);
return generateErrorView(e.getCode(), description, request, service);
}
}
val assertion = validateServiceTicket(service, serviceTicketId);
if (!validateAssertion(request, serviceTicketId, assertion, service)) {
val description = getTicketValidationErrorDescription(CasProtocolConstants.ERROR_CODE_INVALID_TICKET, new Object[]{serviceTicketId}, request);View on GitHub (pinned to e7288fc434)