Search code examples
spring-securitygmail-apispring-oauth2

Incremental authorization for Google OAuth2 Sign in with Spring Security


I was wondering if there is a way for authorizing incrementally with Spring Security (as mentioned here)

By default spring security provides basic profile access when using Google sign OAuth verification. That flow is correct. I would however want to request for additional scopes (Gmail Read, Calendar read etc) on certain URL endpoints.

I have already tried using the @PreAuthorize property on the endpoint along with enabling @EnableGlobalMethodSecurity(prePostEnabled = true) as in the code.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

    @Override

protected MethodSecurityExpressionHandler createExpressionHandler() {
    return new OAuth2MethodSecurityExpressionHandler();
}

}

Security Configuration Class:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
            .antMatchers("/", "/error", "/privacy", "/css/**", "/images/**", "/js/**", "/fonts/**")
            .permitAll().anyRequest().authenticated().and().oauth2Login().and().logout().logoutSuccessUrl("/");
    http.csrf().disable();
    http.headers().frameOptions().disable();

   }
}

Solution

  • I have found a workaround. I have implemented a custom AccessDeniedHandler. Check for the exception and the URL from which it is coming from. If the URL is one where a higher scope is required I redirect the request to google authentication with extra scopes added.

    This is a workaround, the real solution is still open.

    public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    
    @Value("${spring.security.oauth2.client.registration.google.client-id}")
    private String clientId;
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        if (accessDeniedException.getMessage().equalsIgnoreCase("Insufficient scope for this resource")) {
            response.sendRedirect("https://accounts.google.com/o/oauth2/v2/auth?client_id=" + clientId
                            + "&response_type=code&scope=https://www.googleapis.com/auth/gmail.readonly&redirect_uri="
                            + request.getServerName() + "/xyz");
        }
    }
    
    }