spring-projects/spring-security · error · OAuth2AuthenticationException

invalid_request

invalid_request

Error message

OpenID Connect 1.0 Logout Request Parameter: post_logout_redirect_uri

What it means

Raised by OidcLogoutAuthenticationValidator.validatePostLogoutRedirectUri during an OIDC RP-initiated logout when the post_logout_redirect_uri supplied in the logout request is not registered verbatim in the client's RegisteredClient.postLogoutRedirectUris. Per the OpenID Connect RP-Initiated Logout spec, the URI must exactly match a pre-registered value, and the error uses invalid_request.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationValidator.java:69

	public static final Consumer<OidcLogoutAuthenticationContext> DEFAULT_POST_LOGOUT_REDIRECT_URI_VALIDATOR = OidcLogoutAuthenticationValidator::validatePostLogoutRedirectUri;

	private final Consumer<OidcLogoutAuthenticationContext> authenticationValidator = DEFAULT_POST_LOGOUT_REDIRECT_URI_VALIDATOR;

	@Override
	public void accept(OidcLogoutAuthenticationContext authenticationContext) {
		this.authenticationValidator.accept(authenticationContext);
	}

	private static void validatePostLogoutRedirectUri(OidcLogoutAuthenticationContext authenticationContext) {
		OidcLogoutAuthenticationToken oidcLogoutAuthentication = authenticationContext.getAuthentication();
		RegisteredClient registeredClient = authenticationContext.getRegisteredClient();
		if (StringUtils.hasText(oidcLogoutAuthentication.getPostLogoutRedirectUri())
				&& !registeredClient.getPostLogoutRedirectUris()
					.contains(oidcLogoutAuthentication.getPostLogoutRedirectUri())) {
			OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST,
					"OpenID Connect 1.0 Logout Request Parameter: post_logout_redirect_uri",
					"https://openid.net/specs/openid-connect-rpinitiated-1_0.html#ValidationAndErrorHandling");
			throw new OAuth2AuthenticationException(error);
		}
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Add the exact URI to the client registration: registeredClient.postLogoutRedirectUri("https://app.example.com/logged-out") and re-register/persist the client
  2. Send the post_logout_redirect_uri in the logout request exactly as registered (byte-for-byte: scheme, host, port, path, no trailing slash drift)
  3. Log the received value and diff it against RegisteredClient.getPostLogoutRedirectUris() to find the mismatch
  4. If the URI is legitimately variable, register all allowed variants (each host/port/path combination)

Example fix

// before
RegisteredClient.withRegisteredClient(existing)
    .redirectUris(uris -> uris.add("https://app.example.com/callback"))
    .build(); // no post-logout redirect URI registered
// after
RegisteredClient.withRegisteredClient(existing)
    .redirectUris(uris -> uris.add("https://app.example.com/callback"))
    .postLogoutRedirectUri("https://app.example.com/logged-out")
    .build();
Defensive patterns

Strategy: validation

Validate before calling

Set<String> registered = Set.of("https://app.example.com/logged-out");
String requested = params.getFirst("post_logout_redirect_uri");
if (requested != null && !registered.contains(requested)) {
    // do not send post_logout_redirect_uri, or fix it to match registration
    params.remove("post_logout_redirect_uri");
}

Type guard

boolean isRegisteredPostLogoutUri(String uri, RegisteredClient client) {
    return uri != null && client.getPostLogoutRedirectUris().contains(uri);
}

Try / catch

try {
    redirectStrategy.sendRedirect(request, response, logoutUrl);
} catch (OAuth2AuthenticationException e) {
    if (e.getError().getDescription().contains("post_logout_redirect_uri")) {
        // fall back to logout without redirect URI
        response.sendRedirect("/connect/logout?id_token_hint=" + idToken);
    }
}

Prevention

When it happens

Trigger: A logout request like GET /connect/logout?id_token_hint=...&post_logout_redirect_uri=X where X differs from (or was never added to) registeredClient.getPostLogoutRedirectUris — even a trailing-slash, case, or scheme (http vs https) difference fails the contains() check.

Common situations: Front-end apps passing a dynamically built URL (different port, localhost vs 127.0.0.1, trailing slash) instead of the exact registered URI; clients migrated from OAuth2-only config where postLogoutRedirectUris was never configured; staging vs production hosts mismatch.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


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