diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java
new file mode 100644
index 0000000000..90a79a7bf8
--- /dev/null
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.oauth2.client.userinfo;
+
+import java.net.UnknownHostException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import com.nimbusds.oauth2.sdk.ErrorObject;
+import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
+
+import net.minidev.json.JSONObject;
+import reactor.core.publisher.Mono;
+
+/**
+ * An implementation of an {@link ReactiveOAuth2UserService} that supports standard OAuth 2.0 Provider's.
+ *
+ * For standard OAuth 2.0 Provider's, the attribute name used to access the user's name
+ * from the UserInfo response is required and therefore must be available via
+ * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails.UserInfoEndpoint#getUserNameAttributeName() UserInfoEndpoint.getUserNameAttributeName()}.
+ *
+ * NOTE: Attribute names are not standardized between providers and therefore will vary.
+ * Please consult the provider's API documentation for the set of supported user attribute names.
+ *
+ * @author Rob Winch
+ * @since 5.1
+ * @see ReactiveOAuth2UserService
+ * @see OAuth2UserRequest
+ * @see OAuth2User
+ * @see DefaultOAuth2User
+ */
+public class DefaultReactiveOAuth2UserService implements ReactiveOAuth2UserService {
+ private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
+ private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri";
+ private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE = "missing_user_name_attribute";
+
+ private WebClient webClient = WebClient.create();
+
+ @Override
+ public Mono loadUser(OAuth2UserRequest userRequest)
+ throws OAuth2AuthenticationException {
+ return Mono.defer(() -> {
+ Assert.notNull(userRequest, "userRequest cannot be null");
+
+ String userInfoUri = userRequest.getClientRegistration().getProviderDetails()
+ .getUserInfoEndpoint().getUri();
+ if (!StringUtils.hasText(
+ userInfoUri)) {
+ OAuth2Error oauth2Error = new OAuth2Error(
+ MISSING_USER_INFO_URI_ERROR_CODE,
+ "Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: "
+ + userRequest.getClientRegistration().getRegistrationId(),
+ null);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+ String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
+ .getUserNameAttributeName();
+ if (!StringUtils.hasText(userNameAttributeName)) {
+ OAuth2Error oauth2Error = new OAuth2Error(
+ MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE,
+ "Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: "
+ + userRequest.getClientRegistration().getRegistrationId(),
+ null);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+
+ ParameterizedTypeReference