spring-projects/spring-security · error · HttpMessageNotReadableException

An error occurred reading the OAuth 2.0 Device…

Error message

An error occurred reading the OAuth 2.0 Device Authorization Response: ${ex.getMessage()}

What it means

This HttpMessageNotReadableException is thrown by OAuth2DeviceAuthorizationResponseHttpMessageConverter.readInternal when the JSON device authorization response from the authorization server cannot be converted into an OAuth2DeviceAuthorizationResponse. It wraps any exception (parse error, missing required parameters like device_code or verification_uri, type mismatches) produced by the JSON message converter or the parameter converter. The original cause message is appended for diagnosis.

Solutions

  1. Log the wrapped cause (ex.getCause()) to see the actual conversion failure.
  2. Verify the device authorization endpoint URL returns application/json per RFC 8628.
  3. Check the response contains required parameters: device_code, verification_uri (and expires_in/user_code as configured).
  4. Inspect for a proxy/gateway rewriting the response body (HTML error pages).
  5. Set the converter's jsonMessageConverter (MappingJackson2HttpMessageConverter) so Jackson is on the classpath and configured.

Example fix

// before
OAuth2DeviceAuthorizationResponse response = converter.read(OAuth2DeviceAuthorizationResponse.class, inputMessage); // may throw
// after
try {
    OAuth2DeviceAuthorizationResponse response = converter.read(OAuth2DeviceAuthorizationResponse.class, inputMessage);
} catch (HttpMessageNotReadableException ex) {
    logger.error("Device authorization response read failed", ex.getCause());
    throw ex;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!contentTypeCompatible(MediaType.APPLICATION_JSON)) {
    throw new IllegalArgumentException("Device authorization response must be JSON");
}

Try / catch

try {
    OAuth2DeviceAuthorizationResponse r = converter.read(OAuth2DeviceAuthorizationResponse.class, inputMessage);
} catch (HttpMessageNotReadableException ex) {
    logger.error("Device auth response unreadable", ex.getCause());
    throw new OAuth2AuthorizationException(new OAuth2Error("invalid_device_authorization_response", ex.getMessage(), null), ex);
}

Prevention

When it happens

Trigger: Calling readInternal/read on an OAuth2DeviceAuthorizationResponseHttpMessageConverter with a response body that is not valid JSON, is not a JSON object, or lacks required parameters (device_code, verification_uri) that OAuth2DeviceAuthorizationResponseParametersConverter requires.

Common situations: The device authorization endpoint returns an HTML error page instead of JSON (proxy, wrong URL), returns an error payload with HTTP 400 (e.g. authorization_pending is misused on this endpoint), or a custom message converter produces unexpected types.

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/26d91add59db8ea3. Report an issue: GitHub.

Appendix: source

Thrown at oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2DeviceAuthorizationResponseHttpMessageConverter.java:89

	}

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

	@Override
	@SuppressWarnings("unchecked")
	protected OAuth2DeviceAuthorizationResponse readInternal(Class<? extends OAuth2DeviceAuthorizationResponse> clazz,
			HttpInputMessage inputMessage) throws HttpMessageNotReadableException {

		try {
			Map<String, Object> deviceAuthorizationResponseParameters = (Map<String, Object>) this.jsonMessageConverter
				.read(STRING_OBJECT_MAP.getType(), null, inputMessage);
			return this.deviceAuthorizationResponseConverter.convert(deviceAuthorizationResponseParameters);
		}
		catch (Exception ex) {
			throw new HttpMessageNotReadableException(
					"An error occurred reading the OAuth 2.0 Device Authorization Response: " + ex.getMessage(), ex,
					inputMessage);
		}
	}

	@Override
	protected void writeInternal(OAuth2DeviceAuthorizationResponse deviceAuthorizationResponse,
			HttpOutputMessage outputMessage) throws HttpMessageNotWritableException {

		try {
			Map<String, Object> deviceAuthorizationResponseParameters = this.deviceAuthorizationResponseParametersConverter
				.convert(deviceAuthorizationResponse);
			this.jsonMessageConverter.write(deviceAuthorizationResponseParameters, STRING_OBJECT_MAP.getType(),
					MediaType.APPLICATION_JSON, outputMessage);
		}
		catch (Exception ex) {
			throw new HttpMessageNotWritableException(
					"An error occurred writing the OAuth 2.0 Device Authorization Response: " + ex.getMessage(), ex);

View on GitHub (pinned to 96852e8860)