spring-projects/spring-security · error · HttpMessageNotReadableException

An error occurred reading the OAuth 2.0 Client Registration:

Error message

An error occurred reading the OAuth 2.0 Client Registration: + ex.getMessage()

What it means

OAuth2ClientRegistrationHttpMessageConverter.readInternal wraps any exception raised while reading the request/response body as JSON and converting it to an OAuth2ClientRegistration. The JSON converter parses the Map<String,Object> and clientRegistrationConverter.convert() maps it to the typed object; any failure (malformed JSON, missing/invalid registration fields) is rethrown as org.springframework.http.converter.HttpMessageNotReadableException with the cause attached. This means the client registration document could not be read or validated.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/http/converter/OAuth2ClientRegistrationHttpMessageConverter.java:93

		this.jsonMessageConverter = converter;
	}

	@Override
	protected boolean supports(Class<?> clazz) {
		return OAuth2ClientRegistration.class.isAssignableFrom(clazz);
	}

	@Override
	@SuppressWarnings("unchecked")
	protected OAuth2ClientRegistration readInternal(Class<? extends OAuth2ClientRegistration> clazz,
			HttpInputMessage inputMessage) throws HttpMessageNotReadableException {
		try {
			Map<String, Object> clientRegistrationParameters = (Map<String, Object>) this.jsonMessageConverter
				.read(STRING_OBJECT_MAP.getType(), null, inputMessage);
			return this.clientRegistrationConverter.convert(clientRegistrationParameters);
		}
		catch (Exception ex) {
			throw new HttpMessageNotReadableException(
					"An error occurred reading the OAuth 2.0 Client Registration: " + ex.getMessage(), ex,
					inputMessage);
		}
	}

	@Override
	protected void writeInternal(OAuth2ClientRegistration clientRegistration, HttpOutputMessage outputMessage)
			throws HttpMessageNotWritableException {
		try {
			Map<String, Object> clientRegistrationParameters = this.clientRegistrationParametersConverter
				.convert(clientRegistration);
			this.jsonMessageConverter.write(clientRegistrationParameters, STRING_OBJECT_MAP.getType(),
					MediaType.APPLICATION_JSON, outputMessage);
		}
		catch (Exception ex) {
			throw new HttpMessageNotWritableException(
					"An error occurred writing the OAuth 2.0 Client Registration: " + ex.getMessage(), ex);
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Check the cause of the HttpMessageNotReadableException — if it is a JSON parse error the body is malformed; log the raw body to see what was actually returned.
  2. Verify the response Content-Type is application/json and the endpoint actually returns a JSON registration document, not an HTML error page.
  3. Validate the registration JSON against the OAuth2 client registration schema (required fields present) before/after conversion.
  4. Ensure the JSON converter configured via setJsonMessageConverter supports the incoming MediaType.
  5. Relax or correct a custom Converter registered with setClientRegistrationConverter if it rejects a valid registration.

Example fix

// before
ResponseEntity<String> resp = rest.getForEntity(registrationUri, String.class);
OAuth2ClientRegistration reg = converter.read(OAuth2ClientRegistration.class, new MockClientHttpResponse(resp.getBody(), resp.getHeaders())); // fails on HTML bodies
// after
if (!resp.getHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_JSON)) {
  throw new IllegalStateException("Registration endpoint returned non-JSON: " + resp.getBody());
}
OAuth2ClientRegistration reg = converter.read(OAuth2ClientRegistration.class, new MockClientHttpResponse(resp.getBody(), resp.getHeaders()));
Defensive patterns

Strategy: validation

Validate before calling

// before reading
if (body == null || body.isBlank()) throw new OAuth2IntrospectionException("empty registration body");
objectMapper.readTree(body); // throws if malformed JSON
if (!contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) throw new IllegalArgumentException("non-JSON content type");

Try / catch

try {
  return converter.read(OAuth2ClientRegistration.class, inputMessage);
} catch (HttpMessageNotReadableException e) {
  logger.warn("Invalid client registration response: {}", e.getCause().toString());
  throw new OAuth2ClientRegistrationException("Unreadable client registration", e);
}

Prevention

When it happens

Trigger: Calling OAuth2ClientRegistrationHttpMessageConverter.read() (via readInternal) when the body is not parseable JSON (syntax error, wrong Content-Type), the JSON converter throws, or the clientRegistration Converter.convert() throws because required fields (client_id, authorization/token/revocation endpoints, etc.) are missing or invalid.

Common situations: The authorization server / registration endpoint returns HTML or an empty/error body instead of JSON; Content-Type is not application/json so the JSON converter refuses to read; an OpenID Provider publishes an incomplete or non-conformant registration response (missing registration_client_uri fields); a custom clientRegistrationConverter is too strict about optional fields.

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


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