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
- URL-encode all query parameters and path segments in each redirect URI and re-submit the registration request
- Ensure each URI parses: new URI(uri) in a pre-check before calling the registration endpoint
- 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
- Percent-encode query/path components in redirect URIs
- Validate every URI client-side before submitting registration
- Keep each URI a distinct JSON array element
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
- Invalid Client Registration: + fieldName
- Invalid Client Registration: + fieldName
- targetUri must be a valid URL
- targetUri cannot contain query or fragment parts
- invalid_request
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/e2b129aafdcaa0e4.
Report an issue: GitHub.