7

I want to secure my application with Spring Security, using OAuth 2. However, I don't want the server to redirect incoming unauthorized requests, but instead to respond with HTTP 401. Is it possible?

Example: this code redirects requests to a default login page.

application.properties

spring.security.oauth2.client.registration.google.client-id=...
spring.security.oauth2.client.registration.google.client-secret=...

AuthConfig.java

@Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/secured/**").authenticated()
            .anyRequest().permitAll()
            .and()
            .oauth2Login();


        // https://stackoverflow.com/questions/31714585/spring-security-disable-login-page-redirect
        // deos not work
        // .and()
        // .formLogin().successHandler((request, response, authentication) -> {});
    }
}
denov
  • 11,180
  • 2
  • 27
  • 43
nagy.zsolt.hun
  • 6,292
  • 12
  • 56
  • 95

3 Answers3

9

You need to create new authentication entry point and set it in configuration.

@Configuration
public class AuthConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
            .authenticationEntryPoint(new AuthenticationEntryPoint())
            .and()
            .authorizeRequests()
            .antMatchers("/secured/**").authenticated()
            .anyRequest().permitAll()
            .and()
            .oauth2Login();
    }
}

public class AuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {    
    public AuthenticationEntryPoint()  {
        super("");
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendError(401, "Unauthorized");
    }
}
Petr
  • 91
  • 1
  • 3
3

You need to set oauth2Login.loginPage in your HttpSecurity config and create a controller mapping to return whatever you want. Here's a simple example.

So in your security config

http
 .authorizeRequests()
    .antMatchers("/noauth").permitAll()
  .oauth2Login()
    .loginPage("/noauth")

In a controller

@GetMapping("/noauth")
public ResponseEntity<?> noAuth() {
    Map<String, String> body = new HashMap<>();
    body.put("message", "unauthorized");
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(body);
}

You can pass a map or pojo to the body method.

denov
  • 11,180
  • 2
  • 27
  • 43
0

I would like to expand on Petr's answer by explaining that apparently for the time being first of all, the default login page is shown when there are more than one OAuth2 configured providers. I would expect that Spring Boot would have a smart trick to bypass this page easily and choose the right provider automatically, basing e.g. on the existence of the provider's client ID in the original request. I found out the hard way that this is not the case. So the way to do this is.. this not very apparent trick of providing a custom handler for failures - that will REDIRECT the user to the correct OAuth2 endpoint for each provider, based on the original HTTP request URL. I tried this and it works and I spent a whole day trying all manners of other solutions - my original scenario was to pass additional parameters to OAuth2 scheme in order to be able to get them back on successful authentication - they used to do this appending Base64 encoded information to the "state" URL request parameter, but Spring Security does not allow this at the moment. So the only alternative was to call a Spring Security-protected URL with those parameters already there, so when the successful authentication happens, this URL is accessed again automatically with those parameters intact.

Related: Multiple Login endpoints Spring Security OAuth2

hello_earth
  • 1,442
  • 1
  • 25
  • 39