spring-projects/spring-security · error · OAuth2AuthenticationException
invalid_request
invalid_request
Error message
OAuth 2.0 Client Registration Error: ${ex.getMessage()} What it means
OAuth2ClientRegistrationAuthenticationConverter wraps any exception raised while parsing a dynamic client registration request (RFC 7591) into an OAuth2AuthenticationException with code invalid_request and description "OAuth 2.0 Client Registration Error: <original message>". The catch-all in convert() means any failure deserializing/validating the registration JSON body surfaces under this single message, preserving the cause in the exception.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2ClientRegistrationAuthenticationConverter.java:63
*/
public final class OAuth2ClientRegistrationAuthenticationConverter implements AuthenticationConverter {
private final HttpMessageConverter<OAuth2ClientRegistration> clientRegistrationHttpMessageConverter = new OAuth2ClientRegistrationHttpMessageConverter();
@Override
public Authentication convert(HttpServletRequest request) {
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
OAuth2ClientRegistration clientRegistration;
try {
clientRegistration = this.clientRegistrationHttpMessageConverter.read(OAuth2ClientRegistration.class,
new ServletServerHttpRequest(request));
}
catch (Exception ex) {
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST,
"OAuth 2.0 Client Registration Error: " + ex.getMessage(),
"https://datatracker.ietf.org/doc/html/rfc7591#section-3.2.2");
throw new OAuth2AuthenticationException(error, ex);
}
return new OAuth2ClientRegistrationAuthenticationToken(principal, clientRegistration);
}
}
View on GitHub (pinned to 96852e8860)
Solutions
- Look at the cause (ex.getMessage() appears in the description) to see the actual parse/validation failure.
- Validate the registration JSON against RFC 7591 metadata: required fields such as client_name, redirect_uris, grant_types, token_endpoint_auth_method.
- Send the request with Content-Type: application/json and a syntactically valid JSON body.
- Catch OAuth2AuthenticationException on the client side and surface the error_description from the registration endpoint's 400 response.
Example fix
// before: malformed registration payload
{"client_name":"my-app","redirect_uris":"https://app/callback"}
// after
{"client_name":"my-app",
"redirect_uris":["https://app.example.com/callback"],
"grant_types":["authorization_code"],
"token_endpoint_auth_method":"client_secret_basic"} Defensive patterns
Strategy: try-catch
Validate before calling
function validateRegistrationPayload(payload) {
const errors = [];
if (typeof payload !== 'object' || payload === null) errors.push('body must be a JSON object');
if (!Array.isArray(payload.redirect_uris) || payload.redirect_uris.length === 0) errors.push('redirect_uris must be a non-empty array');
if (!Array.isArray(payload.grant_types) || payload.grant_types.length === 0) errors.push('grant_types must be a non-empty array');
if (!payload.token_endpoint_auth_method) errors.push('token_endpoint_auth_method is required');
return errors;
} Type guard
function isRegistrationPayload(p) {
return p != null && typeof p === 'object'
&& typeof p.client_name === 'string'
&& Array.isArray(p.redirect_uris)
&& Array.isArray(p.grant_types);
} Try / catch
try {
response = registerClient(registrationJson);
} catch (OAuth2AuthenticationException e) {
OAuth2Error err = e.getError();
logger.error("Client registration failed ({}): {} cause={}",
err.getErrorCode(), err.getDescription(),
e.getCause() != null ? e.getCause().getMessage() : "n/a");
// fix payload per the cause message and retry
} Prevention
- Validate registration JSON against RFC 7591 metadata fields before POSTing.
- Always set Content-Type: application/json on registration requests.
- Generate payloads programmatically (serialize typed objects) rather than hand-writing JSON.
- Log the cause of OAuth2AuthenticationException — the wrapped exception holds the real parse error.
When it happens
Trigger: A POST to the client registration endpoint with a body that fails to parse as a ClientRegistration payload (invalid JSON, wrong field types, missing required fields like redirect_uris or token_endpoint_auth_method, or any other exception thrown by the underlying request parser).
Common situations: Sending registration metadata with a wrong-typed field (e.g. numeric grant type); omitting required RFC 7591 fields; sending a content-type other than application/json; malformed JSON from a template or script; provisioning clients with an automation script that has drifted from the expected schema.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- invalid_scope
- Invalid Client Registration: + fieldName
- server_error
- Invalid Client Registration: + fieldName
- Invalid Client Registration: + fieldName
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/0cbc4e4427f805a3.
Report an issue: GitHub.