Skip to content

Single page application (SPA) not redirected to OAuth2 provider via Spring Gateway #10843

Closed
@straurob

Description

@straurob

Preface

I'm trying to setup a proof-of-concept like in the following diagram:

  • SPA is a VueJS application.
  • Gateway and API service are Spring Boot applications (version 2.6.3).
  • OAuth2 provider is Keycloak.

component overview

Observations

Scenario 1 (browser without SPA)

When I use the browser without the SPA, then the following workflow works as intended:

  1. Browser hits http://localhost:8555/api/messages.
  2. Gateway redirects to Keycloak login form.
  3. After successful authentication, the browser can access http://localhost:8555/api/messages and a SESSION cookie is created.
  4. The response from /api/messages is shown in the browser.

Scenario 2 (browser with SPA)

This is the scenario I'd like to actually realize. The observed workflow here is:

  1. User calls SPA on http://localhost:8093.
  2. SPA fires a GET request to http://localhost:8555/api/messages.
  3. The user is not redirected to the authentication provider.

Instead, there a several messages in the browser console indicating CORS issues.

Console

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth?response_type=code&client_id=my-client&state=vpgnHaxh-5nb_LxksYL1a-PRU0tzuHR5itVvw1ovD-E%3D&redirect_uri=http://localhost:8555/login/oauth2/code/keycloak. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

Network Traffic

CORS messages in console

As far as I can see, the following is happening:

  1. GET to http://localhost:8555/api/messages is answered with a 302 and location /oauth2/authorization/keycloak.
  2. Another GET to http://localhost:8555/oauth2/authorization/keycloak is answered with a 302 and Location: http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth?response_type=code&client_id=my-client&state=vpgnHaxh-5nb_LxksYL1a-PRU0tzuHR5itVvw1ovD-E%3D&redirect_uri=http://localhost:8555/login/oauth2/code/keycloak
  3. GET to http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth?response_type=code&client_id=my-client&state=vpgnHaxh-5nb_LxksYL1a-PRU0tzuHR5itVvw1ovD-E%3D&redirect_uri=http%3A%2F%2Flocalhost%3A8555%2Flogin%2Foauth2%2Fcode%2Fkeycloak is answered with 200.

But all of them have CORS issues.

Spring Boot Implementation

Gateway

application.yml

server:
  port: 8555

spring:
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: http://localhost:8080/auth/realms/demo
            user-name-attribute: preferred_username
        registration:
          keycloak:
            provider: keycloak
            client-id: my-client
            client-secret: my-secret
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"
  cloud:
    gateway:
      default-filters:
        - TokenRelay
        - RemoveRequestHeader=Cookie
      routes:
        - id: api-service
          uri: http://localhost:8092
          predicates:
            - Path=/api/**

SecurityConfiguration

@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setExposedHeaders(Arrays.asList("*"));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
        httpSecurity
                .csrf().disable()
                .oauth2Login()
                .and()
                .authorizeExchange().anyExchange().authenticated();
        return httpSecurity.build();
    }
}

Keycloak Client

Keycloak client configuration

Metadata

Metadata

Assignees

Labels

for: stackoverflowA question that's better suited to stackoverflow.com

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions