Search code examples
springspring-securitykeycloakspring-security-oauth2keycloak-rest-api

Spring Cloud Gateway redirects to Keycloak login page although Bearer token is set


I am using a setup with Keycloak as Identity Provider, Spring Cloud Gateway as API Gateway and multiple Microservices. I can receive a JWT via my Gateway (redirecting to Keycloak) via http://localhost:8050/auth/realms/dev/protocol/openid-connect/token.

I can use the JWT to access a resource directly located at the Keycloak server (e.g. http://localhost:8080/auth/admin/realms/dev/users). But when I want to use the Gateway to relay me to the same resource (http://localhost:8050/auth/admin/realms/dev/users) I get the Keycloak Login form as response.

My conclusion is that there must me a misconfiguration in my Spring Cloud Gateway application.

This is the Security Configuration in the Gateway:

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, ReactiveClientRegistrationRepository clientRegistrationRepository) {

        // Authenticate through configured OpenID Provider
        http.oauth2Login();

        // Also logout at the OpenID Connect provider
        http.logout(logout -> logout.logoutSuccessHandler(
                new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository)));

        //Exclude /auth from authentication
        http.authorizeExchange().pathMatchers("/auth/realms/ahearo/protocol/openid-connect/token").permitAll();

        // Require authentication for all requests
        http.authorizeExchange().anyExchange().authenticated();

        // Allow showing /home within a frame
        http.headers().frameOptions().mode(Mode.SAMEORIGIN);

        // Disable CSRF in the gateway to prevent conflicts with proxied service CSRF
        http.csrf().disable();
        return http.build();
    }
}

This is my application.yaml in the Gateway:

spring:
  application:
    name: gw-service
  cloud:
    gateway:
      default-filters:
        - TokenRelay
      discovery:
        locator:
          lower-case-service-id: true
          enabled: true
      routes:
        - id: auth
          uri: http://localhost:8080
          predicates:
            - Path=/auth/**

  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: 'api-gw'
            client-secret: 'not-relevant-but-correct'
            authorizationGrantType: authorization_code
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            scope: openid,profile,email,resource.read
        provider:
          keycloak:
            issuerUri: http://localhost:8080/auth/realms/dev
            user-name-attribute: preferred_username

server:
  port: 8050
eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka
    register-with-eureka: true
    fetch-registry: true

How can I make the Gateway able to know that the user is authenticated (using the JWT) and not redirect me to the login page?


Solution

  • I bypassed the problem by communicating directly with Keycloak without relaying requests to it via Spring Cloud Gateway.

    That's actually not a workaround but actually best practice/totally ok as far as I understand.