I'm trying to implement the signup phase with Facebook of my Spring webapp using Spring OAuth2. I'm following this guide https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-2/ but something in my code does not work as expected. The object of type OAuth2User has just the id and the name of the facebook account inside the attributes.
In particular inside the @Service class CustomOAuth2UserService inside the method processOAuth2User
private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) {
OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(oAuth2UserRequest.getClientRegistration().getRegistrationId(), oAuth2User.getAttributes());
if(StringUtils.isEmpty(oAuth2UserInfo.getEmail())) {
throw new OAuth2AuthenticationProcessingException("Email not found from OAuth2 provider");
}
...
}
oAuth2User.getAttributes(), as I said, has only two attributes: id and name but not the email.
My CustomOAuth2UserService class is this:
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
@Autowired
private UserService userService;
@Override
public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest);
try {
return processOAuth2User(oAuth2UserRequest, oAuth2User);
} catch (AuthenticationException ex) {
throw ex;
} catch (Exception ex) {
// Throwing an instance of AuthenticationException will trigger the OAuth2AuthenticationFailureHandler
throw new InternalAuthenticationServiceException(ex.getMessage(), ex.getCause());
}
}
private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) {
OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(oAuth2UserRequest.getClientRegistration().getRegistrationId(), oAuth2User.getAttributes());
if(StringUtils.isEmpty(oAuth2UserInfo.getId())) {
throw new RuntimeException("Id not found from OAuth2 provider");
}
FacebookUser user = null;
try {
user = (FacebookUser) userService.getByFacebookId(oAuth2UserInfo.getId());
} catch (UserNotFoundException e) {
user = registerNewUser(oAuth2UserRequest, oAuth2UserInfo);
}
return new CustomUserDetails(user);
}
private FacebookUser registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
FacebookUser user = new FacebookUser(oAuth2UserInfo.getId());
user.setProvider(AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()));
user.setIdentity(new Identity(oAuth2UserInfo.getName()));
user.setEmail(oAuth2UserInfo.getEmail());
return (FacebookUser) userService.addFacebookUser(user);
}
}
which is inserted in the SecurityConfiguration class:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomOAuth2UserService customOAuth2UserService;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.and()
.oauth2Login()
.loginPage("/login")
.userInfoEndpoint()
.userService(customOAuth2UserService);
}
}