title: Spring Boot + Spring Security + Spring OAuth2 + Google Sign in
body: <p>I have setup a small project to implement OAuth2 Login with Google+ API, using Spring Boot (1.5.2), Spring Security and Spring Security OAuth2.</p>
  
  <p>You can find source in: <a href="https://github.com/ccoloradoc/OAuth2Sample" rel="noreferrer">https://github.com/ccoloradoc/OAuth2Sample</a></p>
  
  <p>I am able to authenticate with google and pull out user information. However, after I logout I cannot login again since I got a "400 Bad Request", after I attempt to connect "<a href="https://accounts.google.com/o/oauth2/auth" rel="noreferrer">https://accounts.google.com/o/oauth2/auth</a>" with my RestTemplate to invoke google api.</p>
  
  <p>See Filter attemptAuthentication method for further reference.</p>
  
  <p>Here is my Security configuration class</p>
  
  <pre><code>@Configuration
  @EnableGlobalAuthentication
  @EnableOAuth2Client
  @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
  @PropertySource(value = {"classpath:oauth.properties"})
  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  
  
      @Autowired
      private UserDetailsService userDetailsService;
  
      @Resource
      @Qualifier("accessTokenRequest")
      private AccessTokenRequest accessTokenRequest;
  
      @Autowired
      private OAuth2ClientContextFilter oAuth2ClientContextFilter;
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          // @formatter:off
          http.
                  authorizeRequests()
                  .antMatchers(HttpMethod.GET, "/login","/public/**", "/resources/**","/resources/public/**").permitAll()
                  .antMatchers("/google_oauth2_login").anonymous()
                  .anyRequest().authenticated()
                  .and()
                  .formLogin()
                  .loginPage("/login")
                  .loginProcessingUrl("/login")
                  .defaultSuccessUrl("/")
                  .and()
                  .csrf().disable()
                  .logout()
                  .logoutSuccessUrl("/")
                  .logoutUrl("/logout")
                  .deleteCookies("remember-me")
                  .and()
                  .rememberMe()
                  .and()
                  .addFilterAfter(oAuth2ClientContextFilter,ExceptionTranslationFilter.class)
                  .addFilterAfter(googleOAuth2Filter(),OAuth2ClientContextFilter.class)
                  .userDetailsService(userDetailsService);
          // @formatter:on
      }
  
      @Bean
      @ConfigurationProperties("google.client")
      public OAuth2ProtectedResourceDetails auth2ProtectedResourceDetails() {
          return new AuthorizationCodeResourceDetails();
      }
  
      @Bean
      public OAuth2RestTemplate oauth2RestTemplate() {
          return new OAuth2RestTemplate(auth2ProtectedResourceDetails(),
                  new DefaultOAuth2ClientContext(accessTokenRequest));
      }
  
  
      @Bean
      public GoogleOAuth2Filter googleOAuth2Filter() {
          return new GoogleOAuth2Filter("/google_oauth2_login");
      }
  
      /*
      *  Building our custom Google Provider
      * */
      @Bean
      public GoogleOauth2AuthProvider googleOauth2AuthProvider() {
          return new GoogleOauth2AuthProvider();
      }
  
      /*
      *  Using autowired to assign it to the auth manager
      * */
      @Autowired
      public void configureGlobal(AuthenticationManagerBuilder auth) {
          auth.authenticationProvider(googleOauth2AuthProvider());
      }
  
      @Bean
      public SpringSecurityDialect springSecurityDialect() {
          return new SpringSecurityDialect();
      }
  
      @Bean
      public TokenStore tokenStore() {
          return new InMemoryTokenStore();
      }
  
  }
  </code></pre>
  
  <p>Here is my authentication provider:</p>
  
  <pre><code>public class GoogleOauth2AuthProvider implements AuthenticationProvider {
  
      private static final Logger logger = LoggerFactory.getLogger(GoogleOauth2AuthProvider.class);
  
      @Autowired(required = true)
      private UserDetailsService userDetailsService;
  
      @Override
      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
          logger.info("Provider Manager Executed");
          CustomOAuth2AuthenticationToken token = (CustomOAuth2AuthenticationToken) authentication;
          UserDetailsImpl registeredUser = (UserDetailsImpl) token.getPrincipal();
          try {
              registeredUser = (UserDetailsImpl) userDetailsService
                      .loadUserByUsername(registeredUser.getEmail());
          } catch (UsernameNotFoundException usernameNotFoundException) {
              logger.info("User trying google/login not already a registered user. Register Him !!");
          }
          return token;
      }
  
      @Override
      public boolean supports(Class&lt;?&gt; authentication) {
          return CustomOAuth2AuthenticationToken.class
                  .isAssignableFrom(authentication);
      }
  }
  </code></pre>
  
  <p>UserDetailService is an implementation from spring security core that reads user from database and translate it to a UserDetails POJO that implements spring security core UserDetails.</p>
  
  <p>Here is my filter implementation:</p>
  
  <pre><code>public class GoogleOAuth2Filter extends AbstractAuthenticationProcessingFilter {
  
      /**
       * Logger
       */
      private static final Logger log = LoggerFactory.getLogger(GoogleOAuth2Filter.class);
  
      private static final Authentication dummyAuthentication;
  
      static {
          dummyAuthentication = new UsernamePasswordAuthenticationToken(
                  "dummyUserName23452346789", "dummyPassword54245",
                  CustomUserDetails.DEFAULT_ROLES);
      }
  
      private static final String NAME = "name";
      private static final String EMAIL = "email";
      private static final String PICTURE = "picture";
  
      private static final Logger logger = LoggerFactory
              .getLogger(GoogleOAuth2Filter.class);
  
  
      @Value(value = "${google.authorization.url}")
      private String googleAuhorizationUrl;
  
      public GoogleOAuth2Filter(String defaultFilterProcessesUrl) {
          super(defaultFilterProcessesUrl);
      }
  
      @Autowired
      private UserService userService;
  
      @Autowired
      private OAuth2RestTemplate oauth2RestTemplate;
  
      @Autowired
      @Override
      public void setAuthenticationManager(AuthenticationManager authenticationManager) {
          super.setAuthenticationManager(authenticationManager);
      }
  
      @Override
      public Authentication attemptAuthentication(HttpServletRequest request,
                                                  HttpServletResponse response) throws AuthenticationException,
              IOException, ServletException {
          logger.info("Google Oauth Filter Triggered!!");
          URI authURI;
          try {
              authURI = new URI(googleAuhorizationUrl);
          } catch (URISyntaxException e) {
              log.error("\n\n\n\nERROR WHILE CREATING GOOGLE AUTH URL", e);
              return null;
          }
          SecurityContext context = SecurityContextHolder.getContext();
          // auth null or not authenticated.
          String code = request.getParameter("code");
          Map&lt;String, String[]&gt; parameterMap = request.getParameterMap();
          logger.debug(parameterMap.toString());
          if (StringUtils.isEmpty(code)) {
              // Google authentication in progress. will return null.
              logger.debug("Will set dummy user in context ");
              context.setAuthentication(dummyAuthentication);
              // trigger google oauth2.
              // ERROR ON SECOND LOGIN ATTEMPT
              oauth2RestTemplate.postForEntity(authURI, null, Object.class);
              return null;
          } else {
              logger.debug("Response from Google Recieved !!");
  
              ResponseEntity&lt;Object&gt; forEntity = oauth2RestTemplate.getForEntity(
                      "https://www.googleapis.com/plus/v1/people/me/openIdConnect",
                      Object.class);
  
              @SuppressWarnings("unchecked")
              Map&lt;String, String&gt; profile = (Map&lt;String, String&gt;) forEntity.getBody();
  
              CustomOAuth2AuthenticationToken authenticationToken = getOAuth2Token(
                      profile.get(EMAIL), profile.get(NAME), profile.get(PICTURE));
              authenticationToken.setAuthenticated(false);
  
              return getAuthenticationManager().authenticate(authenticationToken);
          }
      }
  
      private CustomOAuth2AuthenticationToken getOAuth2Token(
              String email, String name, String picture) {
  
          User user = userService.findByEmail(email);
          //Register user
          if(user == null) {
              user = new User(name, email, picture);
              userService.saveOrUpdate(user);
          }
  
          UserDetailsImpl registeredUser = new UserDetailsImpl(name, email, picture);
  
          CustomOAuth2AuthenticationToken authenticationToken =
                  new CustomOAuth2AuthenticationToken(registeredUser);
  
          return authenticationToken;
      }
  
  }
  </code></pre>