spring-projects/spring-security · error · OAuth2AuthenticationException
invalid_user_info_response
invalid_user_info_response
Error message
${userInfoErrorResponse.getErrorObject().getDescription()} What it means
DefaultReactiveOAuth2UserService.loadUser registers an onStatus handler that parses an error response when the UserInfo endpoint returns an HTTP error status. If the body contains a UserInfo error (WWW-Authenticate/OAuth2 error object), it throws OAuth2AuthenticationException with code 'invalid_user_info_response' and the provider-supplied error description as the message.
Source
Thrown at oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java:127
+ userRequest.getClientRegistration().getRegistrationId(),
null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
AuthenticationMethod authenticationMethod = userRequest.getClientRegistration()
.getProviderDetails()
.getUserInfoEndpoint()
.getAuthenticationMethod();
WebClient.RequestHeadersSpec<?> requestHeadersSpec = getRequestHeaderSpec(userRequest, userInfoUri,
authenticationMethod);
// @formatter:off
Mono<Map<String, Object>> userAttributes = requestHeadersSpec.retrieve()
.onStatus(HttpStatusCode::isError, (response) ->
parse(response)
.map((userInfoErrorResponse) -> {
String description = userInfoErrorResponse.getErrorObject().getDescription();
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, description,
null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
})
)
.bodyToMono(DefaultReactiveOAuth2UserService.STRING_OBJECT_MAP)
.mapNotNull((attributes) -> this.attributesConverter.convert(userRequest).convert(attributes));
return userAttributes.map((attrs) -> {
GrantedAuthority authority = new OAuth2UserAuthority(attrs, userNameAttributeName);
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(authority);
OAuth2AccessToken token = userRequest.getAccessToken();
for (String scope : token.getScopes()) {
authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
}
return new DefaultOAuth2User(authorities, attrs, userNameAttributeName);
})
.onErrorMap((ex) -> (ex instanceof UnsupportedMediaTypeException
|| (ex.getCause() != null && ex.getCause() instanceof UnsupportedMediaTypeException)), (ex) -> {
UnsupportedMediaTypeException umte = (ex instanceof UnsupportedMediaTypeException)View on GitHub (pinned to 96852e8860)
Solutions
- Read the description for the provider's error code (e.g. invalid_token) and act: if 401 invalid_token, refresh the access token via the reactive authorized client manager and retry.
- Verify the token's scopes include openid/profile (or whatever claims you need) and request them at authorization time.
- Confirm the token audience/issuer matches the UserInfo endpoint you are calling.
- Handle OAuth2AuthenticationException in your authentication failure handler with a user-facing message instead of leaking the raw error.
Example fix
// before
return userService.loadUser(userRequest); // throws on 401 invalid_token
// after
return authorizedClientManager.authorize(OAuth2AuthorizeRequest
.withClientRegistrationId(registrationId).principal(principal).build())
.flatMap(authorizedClient -> {
if (authorizedClient.getAccessToken().getScopes().containsAll(requiredScopes)) {
return userService.loadUser(userRequest);
}
return Mono.error(new AuthenticationServiceException("Missing scopes for UserInfo"));
}); Defensive patterns
Strategy: try-catch
Validate before calling
OAuth2AccessToken token = authorizedClient.getAccessToken();
boolean tokenFresh = token != null
&& token.getExpiresAt() != null
&& token.getExpiresAt().isAfter(Instant.now().plusSeconds(30));
if (!tokenFresh) {
// refresh via ReactiveOAuth2AuthorizedClientManager before loadUser
} Try / catch
.onErrorResume(OAuth2AuthenticationException.class, ex -> {
if (ex.getError().getDescription().contains("invalid_token")) {
return refreshAndRetry(userRequest); // re-authorize then loadUser again
}
return Mono.error(ex);
}) Prevention
- Refresh access tokens before they expire via the authorized client manager
- Request openid/profile/email scopes needed by the UserInfo endpoint
- Check token audience/issuer matches the provider
- Map OAuth2AuthenticationException to a friendly login-failure page
When it happens
Trigger: The WebClient call to the UserInfo uri returns an error status (4xx/5xx) whose response parses into a UserInfoErrorResponse — e.g. 401 with 'invalid_token' in WWW-Authenticate — during reactive loadUser.
Common situations: Expired or revoked access token sent to UserInfo; insufficient scopes for the userinfo claim; token issued for a different audience; provider rejecting the Bearer header format.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- invalid_id_token
- invalid_user_info_response
- missing_user_info_uri
- missing_user_name_attribute
- invalid_scope
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/6eea6c3ceff9c0b2.
Report an issue: GitHub.