How to configure SecurityConfig without formlogin in new oauth2.0 server?

796 views Asked by At

My spring authorisation server depedency :-

   <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-authorization-server</artifactId>
        <version>1.0.0</version>
    </dependency>

SecurityConfig class for authorization server:-

public class SecurityConfig {

@Autowired
private JwtAuthenticationEntryPoint authenticationEntryPoint;


@Bean
@Order(1)
public SecurityFilterChain asSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .authorizationEndpoint(a -> a.authenticationProviders(getAuthorizationEndPoints()))
            .oidc(Customizer.withDefaults());

    http.exceptionHandling(exception -> exception
            .authenticationEntryPoint(authenticationEntryPoint));

    return http.build();
}

@Bean
@Order(2)
public SecurityFilterChain appSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.cors(c -> c.configurationSource(
            request -> {
                CorsConfiguration config = new CorsConfiguration();
                config.addAllowedOrigin(request.getHeader("Origin"));
                config.setAllowedMethods(List.of("GET", "POST", "DELETE", "LINK", "UNLINK", "PATCH", "PUT", "OPTIONS"));
                config.setAllowedHeaders(List.of("Content-Type, Accept, X-Requested-With, remember-me"));
                config.setAllowCredentials(true);
                config.setExposedHeaders(List.of("Authorization"));
                config.setMaxAge(3600L);
                return config;
            }
    ));

    http
            .httpBasic().disable()
            .formLogin().disable()
            .authorizeHttpRequests()
            .requestMatchers("/authenticate").permitAll()
            .anyRequest().authenticated();

    return http.build();
}

}

Issue :-

  1. When i call below API http://localhost:7171/oauth2/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=http://localhost:3000

it throws

2023-05-16T15:31:51.127+05:30 TRACE 63279 --- [nio-7171-exec-4] o.s.s.w.a.ExceptionTranslationFilter : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access Denied at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98) ~[spring-security-web-6.0.3.jar:6.0.3]

  1. When i am using formlogin(), it use to redirect to HTTP://localhost:7171/login and asks for username and password and returns authorization_code which needs to be entered in below "http://localhost:7171/oauth2/token " which gives OAuth2 token. How to integrate it with UI.

  2. How to write custom authentication to authenticate and it will give the oauth2 token?

IN simple words, I am applying it without a spring-cloud-gateway just a simple implementation using authorization-server I am stuck at the point, when client app hits for authorisation through API like http://localhost:7171/oauth2/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=http://localhost:3000

which will redirect to authorization server login page.

How can i configure authorization server in a way it will authenticate and provide authorization_code to client so that client can apply http://localhost:7171/oauth2/token to get auth token? That's the ask .

1

There are 1 answers

2
ch4mp On

Your authorization server should be configured with form-login (it is its responsibility to authenticate users), and what is an OAuth2 client in your architecture should use Authorization code flow (with PKCE) to get tokens when users are involved.

Your frontend should not have access to user credentials (contain form for login and password). Both password and implicit flows were deprecated for security reasons.

The OAuth2 client should use a library to store tokens and handle all the redirections you are struggling with.

There are currently at least 2 options for defining what is the OAuth2 client:

  • the frontend itself: a mobile app or an application in the browser written with a Javascript based framework (Angular, React, Vue, etc.) and using a lib to configure it as an Oauth2 public client (neither mobile nor browser applications can keep a secret). angular-auth-oidc-client is a sample of a well documented and full-featured client lib (find an equivalent for your framework if using something else than Angular)
  • a Backend For Frontend, a middleware on your servers:
    • configured as an OAuth2 client
    • securing communication with the frontend using sessions (not access tokens)
    • responsible for OAuth2 login (handling authorization code flow) and logout
    • storing tokens in session
    • replacing session cookie with an Authorization header containing a Bearer access token before forwarding a request from the frontend to resource server(s)

The second options is now frequently preferred because:

  • OAuth2 tokens are hidden to the browser and, more importantly to the Javascript code that runs in it (tokens are stored in BFF session, and session cookie should be flagged as HttpOnly)
  • BFF running on a server you trust, it can keep a secret and be configured as a confidential client (you can be confident that tokens are issued to clients you know)

spring-cloud-gateway can be configured as BFF: with spring-boot-starter-oauth2-client and using the TokenRelay filter. I wrote a tutorial on Baeldung.