{"record":{"id":"53411212dfa679fd","repo":"apereo/cas","slug":"callbackurl-cannot-be-authorized","errorCode":null,"errorMessage":"<callbackUrl> cannot be authorized","messagePattern":"<callbackUrl> cannot be authorized","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/handler/support/ProxyAuthenticationHandler.java","lineNumber":45,"sourceCode":"@Slf4j\npublic class ProxyAuthenticationHandler extends AbstractAuthenticationHandler {\n    private final HttpClient httpClient;\n\n    public ProxyAuthenticationHandler(final String name,\n                                      final PrincipalFactory principalFactory,\n                                      final Integer order, final HttpClient httpClient) {\n        super(name, principalFactory, order);\n        this.httpClient = httpClient;\n    }\n\n    @Override\n    public AuthenticationHandlerExecutionResult authenticate(final Credential credential, final Service service) throws Throwable {\n        val httpCredential = (HttpBasedServiceCredential) credential;\n        if (!httpCredential.getService().getProxyPolicy()\n            .isAllowedProxyCallbackUrl(httpCredential.getService(), httpCredential.getCallbackUrl())) {\n            LOGGER.warn(\"Proxy policy for service [{}] cannot authorize the requested callback url [{}].\",\n                httpCredential.getService(), httpCredential.getCallbackUrl());\n            throw new FailedLoginException(httpCredential.getCallbackUrl() + \" cannot be authorized\");\n        }\n\n        LOGGER.debug(\"Attempting to authenticate [{}]\", httpCredential);\n        val callbackUrl = httpCredential.getCallbackUrl();\n        if (!httpClient.isValidEndPoint(callbackUrl)) {\n            throw new FailedLoginException(callbackUrl.toExternalForm() + \" sent an unacceptable response status code\");\n        }\n        val principalId = httpCredential.getCredentialMetadata().getId();\n        val proxyPrincipal = principalFactory.createPrincipal(principalId);\n        return new DefaultAuthenticationHandlerExecutionResult(this, httpCredential, proxyPrincipal);\n    }\n\n    @Override\n    public boolean supports(final Credential credential) {\n        return credential instanceof HttpBasedServiceCredential;\n    }\n\n    @Override","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/handler/support/ProxyAuthenticationHandler.java#L27-L63","documentation":"ProxyAuthenticationHandler.authenticate throws FailedLoginException when the service's ProxyPolicy refuses to authorize the PGT callback URL presented by the HttpBasedServiceCredential. Proxy authentication (proxy-granting tickets) requires the callback URL to pass the service's proxy policy (e.g. RegisteredServiceProxyPolicy regex), otherwise the proxy credential is rejected before any HTTP validation.","triggerScenarios":"A PGT callback credential (pgtUrl) is submitted and httpCredential.getService().getProxyPolicy().isAllowedProxyCallbackUrl(...) returns false — the callback URL doesn't match the registered service's proxy pattern or the proxy policy denies all callbacks.","commonSituations":"Registered service has proxying disabled or its proxy policy regex doesn't match the callback host/URL; callback URL uses http while the pattern allows only https; service registry entry updated and the old proxy pattern no longer matches; client app changed its pgtUrl after deployment.","solutions":["Update the registered service's proxyPolicy (e.g. RegexMatchingRegisteredServiceProxyPolicy) pattern to include the callback URL.","Ensure the callback URL scheme/host matches the policy exactly (https vs http, ports, query strings).","If proxying is intended, confirm the service definition allows proxy authentication and the access strategy permits it.","Change the client application's pgtUrl to one already authorized by the proxy policy.","Check the WARN log naming the service and callback URL to see the exact mismatch."],"exampleFix":"// before (service JSON)\n\"proxyPolicy\": { \"@class\": \"org.apereo.cas.services.RefuseRegisteredServiceProxyPolicy\" }\n// after\n\"proxyPolicy\": { \"@class\": \"org.apereo.cas.services.RegexMatchingRegisteredServiceProxyPolicy\", \"pattern\": \"^https://app\\\\.example\\\\.org/.*\" }","handlingStrategy":"validation","validationCode":"// before requesting a PGT, check the policy client-side if you know the service def\nboolean allowed = registeredService.getProxyPolicy()\n    .isAllowedProxyCallbackUrl(registeredService, callbackUrl);\nif (!allowed) { throw new IllegalArgumentException(\"Callback URL not authorized: \" + callbackUrl); }","typeGuard":null,"tryCatchPattern":"try {\n    return handler.authenticate(credential, service);\n} catch (FailedLoginException e) {\n    if (e.getMessage() != null && e.getMessage().endsWith(\"cannot be authorized\")) {\n        LOGGER.error(\"Proxy callback URL [{}] rejected by service proxy policy\", ((HttpBasedServiceCredential) credential).getCallbackUrl(), e);\n    }\n    throw e;\n}","preventionTips":["Keep proxy policy regexes in the service registry aligned with every pgtUrl your clients use.","Prefer https callback URLs and ensure patterns cover scheme, host, and port.","When changing a client's callback URL, update the registered service definition in the same change."],"tags":["authentication","proxy-authentication","registered-service","url"],"backgroundTag":"invalid-url","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}