spring-projects/spring-security · error · Saml2AuthenticationException

invalid_request

invalid_request

Error message

Logout request used invalid binding

What it means

Saml2LogoutRequestFilter.validateLogoutRequest resolves the binding of the incoming logout request (from the request parameters/transport) and checks it is among the registration's getSingleLogoutServiceBindings(). If the used binding (e.g. REDIRECT) is not in the configured set (e.g. only POST), it throws Saml2AuthenticationException with code invalid_request and message 'Logout request used invalid binding'.

Source

Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java:193

	 */
	public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
		Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
		this.securityContextHolderStrategy = securityContextHolderStrategy;
	}

	private void validateLogoutRequest(HttpServletRequest request, Saml2LogoutRequestValidatorParameters parameters) {
		RelyingPartyRegistration registration = parameters.getRelyingPartyRegistration();
		if (registration.getSingleLogoutServiceLocation() == null) {
			this.logger.trace(
					"Did not process logout request since RelyingPartyRegistration has not been configured with a logout request endpoint");
			throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_DESTINATION,
					"RelyingPartyRegistration has not been configured with a logout request endpoint"));
		}

		Saml2MessageBinding saml2MessageBinding = Saml2MessageBindingUtils.resolveBinding(request);
		if (!registration.getSingleLogoutServiceBindings().contains(saml2MessageBinding)) {
			this.logger.trace("Did not process logout request since used incorrect binding");
			throw new Saml2AuthenticationException(
					new Saml2Error(Saml2ErrorCodes.INVALID_REQUEST, "Logout request used invalid binding"));
		}

		Saml2LogoutValidatorResult result = this.logoutRequestValidator.validate(parameters);
		if (result.hasErrors()) {
			this.logger.debug(LogMessage.format("Failed to validate LogoutRequest: %s", result.getErrors()));
			throw new Saml2AuthenticationException(
					new Saml2Error(Saml2ErrorCodes.INVALID_REQUEST, "Failed to validate the logout request"));
		}
	}

	private void sendLogoutResponse(HttpServletRequest request, HttpServletResponse response,
			Saml2LogoutResponse logoutResponse) throws IOException {
		if (logoutResponse.getBinding() == Saml2MessageBinding.REDIRECT) {
			doRedirect(request, response, logoutResponse);
		}
		else {
			doPost(request, response, logoutResponse);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Align singleLogoutServiceBinding(s) in the registration with what the IDP actually sends (check IDP's SingleLogoutService Binding attribute in metadata)
  2. Re-import IDP metadata so bindings are picked up automatically
  3. Update the IDP's SLO binding setting to match the SP configuration
  4. Verify proxies preserve both query parameters (Redirect binding) and form bodies (POST binding)

Example fix

// before (only POST configured, IDP sends Redirect)
.singleLogoutServiceLocation("https://idp/slo")
.singleLogoutServiceBinding(Saml2MessageBinding.POST)
// after (accept the binding the IDP uses)
.singleLogoutServiceLocation("https://idp/slo")
.singleLogoutServiceBindings(b -> b.addAll(List.of(Saml2MessageBinding.POST, Saml2MessageBinding.REDIRECT)))
Defensive patterns

Strategy: validation

Validate before calling

Saml2MessageBinding inbound = Saml2MessageBindingUtils.resolveBinding(request);
if (!registration.getSingleLogoutServiceBindings().contains(inbound)) {
    log.warn("SLO binding " + inbound + " not enabled for registration");
}

Try / catch

try { /* saml2Logout configuration */ } catch (Saml2AuthenticationException ex) {
    if ("invalid_request".equals(ex.getSaml2Error().getErrorCode())) {
        log.warn("SLO binding mismatch", ex);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
    } else { throw ex; }
}

Prevention

When it happens

Trigger: The IDP sends the LogoutRequest via a binding (Redirect or POST) not listed in the RelyingPartyRegistration's singleLogoutServiceBindings, or the SP config lists the wrong binding(s).

Common situations: IDP metadata advertises Redirect binding but the SP registration was hand-configured with POST only (or vice versa); IDP config changed binding after metadata import; reverse proxy stripping query parameters making Redirect-bound messages look malformed.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/75cdebf1a616e49c. Report an issue: GitHub.