apereo/cas · error

CAS is configured to only accept pushed authorization…

Error message

CAS is configured to only accept pushed authorization requests

What it means

When requirePushedAuthorizationRequests is enabled, the authorize endpoint only accepts requests that supply a request_uri (produced by a prior PAR call). A direct authorize request without request_uri is rejected with HTTP 403 and an error view.

Solutions

  1. Have clients obtain a request_uri via the PAR endpoint and pass it on /authorize
  2. Disable the mode: cas.authn.oidc.discovery.require-pushed-authorization-requests=false
  3. Ensure the PAR request_uri is not blank/truncated when forwarded
  4. Adopt an RP library that advertises and honors 'require_pushed_authorization_requests' in discovery metadata

Example fix

// before
GET /oidc/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=...
// after
POST /oidc/pushAuthRequest?... -> request_uri
GET /oidc/authorize?client_id=client&request_uri=urn:ietf:params:oauth:request_uri:xyz
Defensive patterns

Strategy: validation

Validate before calling

if (requirePar && !params.get('request_uri')) {
  throw new Error('PAR enabled: call the pushed authorization endpoint first and pass request_uri');
}

Type guard

function isParAuthorizeUrl(url, requirePar) {
  return !requirePar || new URL(url).searchParams.has('request_uri');
}

Prevention

When it happens

Trigger: A browser navigation (GET) to /oidc/authorize whose URL ends with 'authorize' and whose parameter map lacks a non-blank request_uri, while requirePushedAuthorizationRequests=true.

Common situations: Same misconfiguration as error 530: PAR enforcement turned on but clients still doing classic front-channel redirects; forgot that even POST-based authorize without request_uri is rejected; discovery metadata not consumed by the RP.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/authorize/OidcAuthorizeEndpointController.java:51

    }

    @GetMapping({
        '/' + OidcConstants.BASE_OIDC_URL + '/' + OAuth20Constants.AUTHORIZE_URL,
        "/**/" + OidcConstants.AUTHORIZE_URL
    })
    @Operation(summary = "Handle OIDC authorization request")
    @Override
    public ModelAndView handleRequest(final HttpServletRequest request, final HttpServletResponse response) throws Throwable {
        val webContext = new JEEContext(request, response);
        if (!getConfigurationContext().getIssuerService().validateIssuer(webContext, List.of(OidcConstants.AUTHORIZE_URL, OAuth20Constants.AUTHORIZE_URL))) {
            LOGGER.warn("CAS cannot accept the authorization request given the issuer is invalid.");
            return OAuth20Utils.writeError(response, OAuth20Constants.INVALID_REQUEST, "Invalid issuer");
        }

        if (getConfigurationContext().getDiscoverySettings().isRequirePushedAuthorizationRequests()
            && webContext.getRequestURL().endsWith(OidcConstants.AUTHORIZE_URL)
            && StringUtils.isBlank(request.getParameter(OidcConstants.REQUEST_URI))) {
            LOGGER.warn("CAS is configured to only accept pushed authorization requests");
            return OAuth20Utils.produceUnauthorizedErrorView(HttpStatus.FORBIDDEN);
        }

        val scopes = getConfigurationContext().getRequestParameterResolver().resolveRequestedScopes(webContext);
        if (scopes.isEmpty() || !scopes.contains(OidcConstants.StandardScopes.OPENID.getScope())) {
            LOGGER.warn("Provided scopes [{}] are undefined by OpenID Connect, which requires that scope [{}] MUST be specified, "
                        + "or the behavior is unspecified. CAS MAY allow this request to be processed for now.",
                scopes, OidcConstants.StandardScopes.OPENID.getScope());
        }
        return super.handleRequest(request, response);
    }

    @PostMapping({
        '/' + OidcConstants.BASE_OIDC_URL + '/' + OAuth20Constants.AUTHORIZE_URL,
        "/**/" + OidcConstants.AUTHORIZE_URL
    })
    @Override
    @Operation(summary = "Handle OIDC authorization request")

View on GitHub (pinned to e7288fc434)