Spring cloud gatewate as oauth2 client + React Front End. Problem Redirecting to login page after Refresh Token Expires

35 views Asked by At

I have a spring cloud gateway as an oauth2 client that is serving a react front end. I am testing how it handles an expired refresh token. With no configuration it would throw a 500 internal server exception. More information can be found here https://github.com/spring-projects/spring-security/issues/11015

To fix this I tried the following:

    @Log4j2
public class ReactiveOAuth2AuthorizedClientManagerCustom implements ReactiveOAuth2AuthorizedClientManager {

    private final ReactiveClientRegistrationRepository clientRegistrationRepository;
    private final ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
    private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager;

    public ReactiveOAuth2AuthorizedClientManagerCustom(ReactiveClientRegistrationRepository clientRegistrationRepository,
                                                       ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.authorizedClientRepository = authorizedClientRepository;
        this.authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
                this.clientRegistrationRepository, this.authorizedClientRepository
        );
    }

    public Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizeRequest authorizeRequest) {
        Assert.notNull(authorizeRequest.getClientRegistrationId(), "Client registration id cannot be null");

        return this.authorizedClientManager.authorize(authorizeRequest)

                .onErrorMap(
                        ClientAuthorizationException.class,
                        error -> {
                            return new ClientAuthorizationRequiredException(authorizeRequest.getClientRegistrationId());
                        });
    }
}

@Log4j2
@Configuration
@EnableWebFluxSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final ReactiveClientRegistrationRepository clientRegistrationRepository;
    private final ServerOAuth2AuthorizedClientRepository authorizedClientRepository;

    @Bean
    @Order(0)
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .oauth2Login(Customizer.withDefaults());
        http.authorizeExchange(exchange -> exchange.anyExchange().authenticated());

        return http.build();
    }

    @Bean
    @Primary
    ReactiveOAuth2AuthorizedClientManager authorizedClientManager() {
        return new ReactiveOAuth2AuthorizedClientManagerCustom(
                this.clientRegistrationRepository, this.authorizedClientRepository
        );
    }

Along with a web filter to handle that exception and redirect to the login page which is server by a spring oauth2 provider

    @Component
@Log4j2
public class AuthorizationRedirectWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return chain.filter(exchange)
                .onErrorResume(ClientAuthorizationRequiredException.class, ex -> redirectToLoginPage(exchange));
    }

    private Mono<Void> redirectToLoginPage(ServerWebExchange exchange) {
        // Set the status code and the location header
        exchange.getResponse().setStatusCode(HttpStatus.SEE_OTHER);
        exchange.getResponse().getHeaders().setLocation(URI.create("/oauth2/authorization/gateway"));

        return exchange.getResponse().setComplete();
    }
}

When the refresh token expires I am redirected to my login page in the auth server as expected. But when I enter my credentials. I am redirected back to my spring cloud gateway /login?error page.

enter image description here

And when I click the login button I am automatically logged in without ever having to enter my credentials. Indicating that my first login was successful and my credentials were not invalid.

The thing I am confused the most about is that on my browser if I navigate directly to /oauth2/authorization/gateway everything works exactly as expected, as I am redirected to my auth server to login, I log in, and then I am redirected back to my react app that the spring cloud gateway is server. So why is it that when I try and do this redirection programically everything falls apart?

For even more context here is my spring cloud gateway config

spring:
  cloud:
    gateway:
      routes:
        - id: resource-server-route
          uri: http://localhost:8080  # Base URL of your resource server
          predicates:
            - Path=/users, /user/**
          filters:
            TokenRelay=

  security:
    oauth2:
      client:
        registration:
          gateway:
            provider: auth-server
            client-id: gateway
            client-secret: secret
            authorization-grant-type: authorization_code
            redirect-uri: http://localhost:8090/login/oauth2/code/{registrationId}
            scope: openid
        provider:
          auth-server:
            issuer-uri: http://localhost:9000
0

There are 0 answers