content: package com.anita.multipleauthapi.security;
  
  import com.anita.multipleauthapi.security.oauth2.*;
  import lombok.RequiredArgsConstructor;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.http.converter.FormHttpMessageConverter;
  import org.springframework.security.authentication.AuthenticationManager;
  import org.springframework.security.config.Customizer;
  import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
  import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
  import org.springframework.security.config.http.SessionCreationPolicy;
  import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  import org.springframework.security.crypto.password.PasswordEncoder;
  import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
  import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
  import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
  import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
  import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
  import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
  import org.springframework.security.web.SecurityFilterChain;
  import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  import org.springframework.web.client.RestTemplate;
  
  import java.util.Arrays;
  
  @Configuration
  @EnableWebSecurity
  @RequiredArgsConstructor
  public class SecurityConfig {
  
      private final static String OAUTH2_BASE_URI = "/oauth2/authorize";
      private final static String OAUTH2_REDIRECTION_ENDPOINT = "/oauth2/callback/*";
  
      private final CustomOAuth2UserService customOAuth2UserService;
      private final OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
      private final OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
      private final HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;
      private final TokenAuthenticationFilter tokenAuthenticationFilter;
      private final ClientRegistrationRepository clientRegistrationRepository;
  
  
      @Bean
      public HttpCookieOAuth2AuthorizationRequestRepository cookieOAuth2AuthorizationRequestRepository() {
          return new HttpCookieOAuth2AuthorizationRequestRepository();
      }
  
      @Bean
      protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
          http.csrf(AbstractHttpConfigurer::disable);
          http.cors(Customizer.withDefaults());
          http.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
          http.formLogin(AbstractHttpConfigurer::disable);
          http.httpBasic(AbstractHttpConfigurer::disable);
  
          http.authorizeHttpRequests(
            auth -> auth
                    .requestMatchers("/token/refresh/**").permitAll()
                    .requestMatchers("/", "/error").permitAll()
                    .requestMatchers("/auth/**", "/oauth2/**").permitAll()
                    .anyRequest()
                    .authenticated()
          );
  
          http
                  .oauth2Login(oauth2 -> oauth2
                          .authorizationEndpoint(authorizationEndpointConfig -> authorizationEndpointConfig
                                  .baseUri(OAUTH2_BASE_URI)
                                  .authorizationRequestRepository(httpCookieOAuth2AuthorizationRequestRepository)
                                  .authorizationRequestResolver(new CustomAuthorizationRequestResolver(clientRegistrationRepository, OAUTH2_BASE_URI))
                          )
                          .redirectionEndpoint(redirectionEndpointConfig -> redirectionEndpointConfig.baseUri(OAUTH2_REDIRECTION_ENDPOINT))
                          .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig.userService(customOAuth2UserService))
                          .tokenEndpoint(tokenEndpointConfig -> tokenEndpointConfig.accessTokenResponseClient(authorizationCodeTokenResponseClient()))
                          .successHandler(oAuth2AuthenticationSuccessHandler)
                          .failureHandler(oAuth2AuthenticationFailureHandler)
                  );
  
          http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
  
          return http.build();
      }
  
      private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeTokenResponseClient() {
          OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
          tokenResponseHttpMessageConverter.setAccessTokenResponseConverter(new CustomAccessTokenResponseConverter());
  
          RestTemplate restTemplate = new RestTemplate(Arrays.asList(new FormHttpMessageConverter(), tokenResponseHttpMessageConverter));
          restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
  
          DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
          tokenResponseClient.setRestOperations(restTemplate);
  
          return tokenResponseClient;
      }
  
      @Bean
      public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
          return authenticationConfiguration.getAuthenticationManager();
      }
  
      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();
      }
  
  }
  