title: Successful Spring OAuth2 login with empty authorities
body: <p>I implemented the login of my Spring Boot web app using OAuth2 and everything works fine. 
  The only problem is that the logged in user does not has the authorities information saved inside the session so each time I request a url and the controller has the annotation @PreAuthorize("hasRole('USER')") I get rejected.</p>
  
  <p>SecurityConfiguration class:</p>
  
  <pre><code>@EnableGlobalMethodSecurity(prePostEnabled = true)
  @EnableWebSecurity
  @EnableJpaRepositories(basePackageClasses = UserRepository.class)
  @Configuration
  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  
      @Autowired
      private CustomOAuth2UserService customOAuth2UserService;
  
      @Autowired
      private CustomUserDetailsService userDetailsService;
  
      @Autowired
      private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
  
      @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()
                  .logout()
                      .logoutSuccessUrl("/")
                      .deleteCookies("JSESSIONID")
                      .invalidateHttpSession(true)
                  .and()
                  .oauth2Login()
                      .loginPage("/login")
                      .failureUrl("/login?error=true")
                  .userInfoEndpoint()
                      .userService(customOAuth2UserService)
                  .and()
                  .failureHandler(oAuth2AuthenticationFailureHandler);
      }
  
  
      @Bean
      public BCryptPasswordEncoder passwordEncoder(){
          return new BCryptPasswordEncoder();
      }
  
      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
      }
  
  }
  </code></pre>
  
  <p>This is the CustomOAuth2UserService class:</p>
  
  <pre><code>@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 (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.getEmail())) {
              throw new RuntimeException("Id not found from OAuth2 provider");
          }
  
          User user;
          try {
              user = userService.getByEmail(oAuth2UserInfo.getEmail());
              if(!user.getProvider().toString().equalsIgnoreCase(oAuth2UserRequest.getClientRegistration().getRegistrationId())) throw new EmailAlreadyTakenException("email-already-taken");
          } catch (UserNotFoundException e) {
              user = registerNewUser(oAuth2UserRequest, oAuth2UserInfo);
          }
  
          return new CustomUserDetails(user);
      }
  
      private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
          User user = new User();
          user.setProvider(AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()));
          Identity identity = new Identity(user);
          if(oAuth2UserInfo.getFirstName() != null &amp;&amp; !oAuth2UserInfo.getFirstName().equalsIgnoreCase(""))
              identity.setFirstName(oAuth2UserInfo.getFirstName());
          if(oAuth2UserInfo.getLastName() != null &amp;&amp; !oAuth2UserInfo.getLastName().equalsIgnoreCase(""))
              identity.setSecondName(oAuth2UserInfo.getLastName());
          user.setIdentity(identity);
          user.setEmail(oAuth2UserInfo.getEmail());
          user.setConfirmedRegistration(true);
          boolean flag = false;
          String username = oAuth2UserInfo.getName().toLowerCase().replaceAll("\\s+", "");
          user.setUsername(username);
          return userService.addFacebookUser(user);
  
      }
  
  }
  </code></pre>
  
  <p>This a part of the application.properties file:</p>
  
  <pre><code>spring.security.oauth2.client.registration.facebook.client-id=***
  spring.security.oauth2.client.registration.facebook.client-secret=***
  spring.security.oauth2.client.registration.facebook.scope=email,public_profile
  
  spring.security.oauth2.client.registration.google.client-id=***
  spring.security.oauth2.client.registration.google.client-secret=***
  spring.security.oauth2.client.registration.google.scope=email,profile
  
  
  spring.security.oauth2.client.provider.facebook.authorizationUri = https://www.facebook.com/v3.0/dialog/oauth
  spring.security.oauth2.client.provider.facebook.tokenUri = https://graph.facebook.com/v3.0/oauth/access_token
  spring.security.oauth2.client.provider.facebook.userInfoUri = https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture
  </code></pre>
  
  <p>Once logged in the user can call this url /users/{username} but when he login with facebook or google through OAuth2, he gets rejected because the authorities list is empty. When he login with his webapp credential, the authorities list contains USER_ROLE and he is allowed to procede.</p>
  
  <pre><code>@PreAuthorize("hasRole('USER')")
      @GetRequest("users/{username}")
      public String getUser(@PathVariable String username, @PathVariable String subsection, Model model, Principal principal) throws IllegalAccessException, UserNotFoundException {
          User user = userService.getByUsername(principal.getName());
          model.addAttribute("user", user);
          return "user";
      }
  </code></pre>
  
  <p>Inside principal object there are:</p>
  
  <p>When logged in with OAuth2:</p>
  
  <ul>
  <li><strong>principal</strong>: type CustomUserDetails (user information)</li>
  <li><strong>authorizedClientRegistrationId</strong>: type String ("google", "facebook")</li>
  <li><strong>authorities</strong>: type Collections$UnmodifiableRandomAccessList (empty)</li>
  <li><strong>details</strong>: null</li>
  <li><strong>authenticated</strong>: type boolean (true)</li>
  </ul>
  
  <p>When logged in with local credentials:</p>
  
  <ul>
  <li><strong>principal</strong>: type CustomUserDetails (user information)</li>
  <li><strong>credentials</strong>: null</li>
  <li><strong>authorities</strong>: type Collections$UnmodifiableRandomAccessList
  
  <ul>
  <li>index:0 type SimpleGrantedAuthority ("USER_ROLE")</li>
  </ul></li>
  <li><strong>details</strong>: type WebAuthenticationDetails (remote address, sessionId)</li>
  <li><strong>authenticated</strong>: type boolean (true)</li>
  </ul>