I have a Spring boot microservice application using Spring Cloud Gateway for exposing microservices to frontend. When I try to call them from my Angular 19 SPA I get a CORS error despite having activated configuration to add Access-Control-Allow-Origin in header. I activated the HttpOnly for delegate the token handeling at backend. When I call login, register or logout endpoint everything works well, but In the header of my application I have a service to get connected user informations, and the calling of this service in onInit getting a 401. You can find bellow configuration files. dashboard:1 Access to XMLHttpRequest at 'http://localhost:8084/api/1.0/users/8aad4849-21eb-4fc1-b852-83e078c2a90e' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. user-account.service.ts:21 Account API error HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: 'Unknown Error', url: 'http://localhost:8084/api/1.0/users/8aad4849-21eb-4fc1-b852-83e078c2a90e', ok: false, …}error: ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: 'error', …}headers: HttpHeaders {headers: Map(0), normalizedNames: Map(0), lazyInit: undefined, lazyUpdate: null}message: "Http failure response for http://localhost:8084/api/1.0/users/8aad4849-21eb-4fc1-b852-83e078c2a90e: 0 Unknown Error"name: "HttpErrorResponse"ok: falsestatus: 0statusText: "Unknown Error"type: undefinedurl: "http://localhost:8084/api/1.0/users/8aad4849-21eb-4fc1-b852-83e078c2a90e"[[Prototype]]: HttpResponseBase Api gateway configuration spring: application: name: api-gateway cloud: gateway: routes: - id: auth-service uri: lb://auth-service predicates: - Path=/api/1.0/auth/** - id: account-service uri: lb://account-service predicates: - Path=/api/1.0/users/** globalcors: corsConfigurations: '[/**]': allowedOrigins: - "http://localhost:4200" allowedMethods: - GET - POST - PUT - DELETE - OPTIONS allowedHeaders: - "*" allowCredentials: true security: oauth2: resourceserver: jwt: issuer-uri: http://localhost:8080/realms/My-Realm_Realm server: port: 8084 error: include-stacktrace: always eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true Security Configuration package com.omb.ombgateway.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository; @Configuration public class SecurityConfig { @Bean public SecurityWebFilterChain gatewaySecurity(ServerHttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) .authorizeExchange(exchanges -> exchanges .pathMatchers("/api/1.0/auth/**", "/actuator/**", "/error").permitAll() .anyExchange().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); return http.build(); } } Accout microservice security config package com.omb.ombaccount.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter()); http .csrf(csrf -> csrf.disable()) .cors(Customizer.withDefaults()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/**").hasAnyRole("USER", "ADMIN") .requestMatchers("/actuator/**", "/h2-console/**").permitAll() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter) ) ); return http.build(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(16); } } Account CORS configuration package com.omb.ombaccount.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; @Configuration public class CorsGlobalConfiguration { @Bean public CorsWebFilter corsWebFilter() { CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.setAllowCredentials(true); corsConfig.addAllowedOrigin("http://localhost:4200"); corsConfig.addAllowedHeader("*"); corsConfig.addAllowedMethod("GET"); corsConfig.addAllowedMethod("POST"); corsConfig.addAllowedMethod("PUT"); corsConfig.addAllowedMethod("DELETE"); corsConfig.addAllowedMethod("OPTIONS"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig); return new CorsWebFilter(source); } } account http client getUserAccount(id: string): Observable<UserAccountModel> { return this.http.get<UserAccountModel>(this.accountBaseUrl + '/'+id, { withCredentials: true }).pipe( catchError(error => { console.error('Account API error', error); return throwError(() => error); }) ); } Continue reading...