spring-projects/spring-security · error · OAuth2AuthenticationException

invalid_redirect_uri

invalid_redirect_uri

Error message

Invalid Client Registration: redirect_uris

What it means

During OIDC client registration (dynamic registration) the validator strictly checks each redirect URI (or post-logout redirect URI): it must be parseable as a URI. If new URI(redirectUri) throws URISyntaxException, registration is rejected with an invalid_redirect_uri error for field 'redirect_uris'.

Source

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

		validateRedirectUrisStrict(postLogoutRedirectUris, "invalid_client_metadata",
				OidcClientMetadataClaimNames.POST_LOGOUT_REDIRECT_URIS);
	}

	private static void validateRedirectUrisStrict(List<String> redirectUris, String errorCode, String fieldName) {
		if (CollectionUtils.isEmpty(redirectUris)) {
			return;
		}
		for (String redirectUri : redirectUris) {
			URI parsed;
			try {
				parsed = new URI(redirectUri);
			}
			catch (URISyntaxException ex) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug(
							LogMessage.format("Invalid request: %s is not parseable ('%s')", fieldName, redirectUri));
				}
				throw createException(errorCode, fieldName);
			}
			if (parsed.getFragment() != null) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug(LogMessage.format("Invalid request: %s contains a fragment ('%s')", fieldName,
							redirectUri));
				}
				throw createException(errorCode, fieldName);
			}
			String scheme = parsed.getScheme();
			if (scheme == null) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug(LogMessage.format("Invalid request: %s has no scheme ('%s')", fieldName, redirectUri));
				}
				throw createException(errorCode, fieldName);
			}
			if (isUnsafeScheme(scheme)) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug(

View on GitHub (pinned to 96852e8860)

Solutions

  1. URL-encode all query parameters and path segments in each redirect URI and re-submit the registration request
  2. Ensure each URI parses: new URI(uri) in a pre-check before calling the registration endpoint
  3. Check the client sends each redirect URI as a separate array element, not a space-separated string

Example fix

// before
"redirect_uris": ["https://example.com/cb?next=/a b"]
// after
"redirect_uris": ["https://example.com/cb?next=%2Fa%20b"]
Defensive patterns

Strategy: validation

Validate before calling

for (String uri : redirectUris) {
    try { new URI(uri); }
    catch (URISyntaxException e) { throw new IllegalArgumentException("unparseable redirect_uri: " + uri); }
}

Try / catch

try {
    clientRegistrationService.save(newRegistration);
} catch (OAuth2AuthenticationException ex) {
    // errorCode invalid_redirect_uri, description names redirect_uris
}

Prevention

When it happens

Trigger: POST to the client registration endpoint with a redirect_uris (or post_logout_redirect_uris) entry that is not a syntactically valid URI, e.g. 'http://exa mple.com/cb' or missing entirely malformed string.

Common situations: Unencoded spaces or special characters in the URI; truncation when copying from docs; scheme-less fragments like 'localhost:8080/cb' mishandled; multi-value field mis-split producing garbage entries.

Related errors


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