'React Spring Oauth2 authorization code grant

I need help to resolve following CORS error.

Access to fetch at 'http://localhost/auth/realms/demo/protocol/openid-connect/auth?response_type=code&client_id=oauth2-demo&scope=openid&state=QQnjRZQ82U2KwgAczZ98u-JR0pUhDXgM4z0wlUOPPhM%3D&redirect_uri=http://localhost:8080/login/oauth2/code/oauth2-demo&nonce=ayTCEaqST3A0oRufr9JBDxvPdHx3SWL3GOTilDBASbE' (redirected from 'http://localhost:8080/authenticate') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I am using Spring Boot Oauth2 client to interact with keycloak Oauth server. I am using react login button to call and fetch the access token from Spring Boot Oauth client by calling URI "http:localhost:8080/authenticate".

When I call the same URL from browser everything works fine and oauth flow completes successfully and return the access token however when I call it from react APP Oauth2 redirects fails with CORS error.

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
    @Bean
    public SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
        http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable();
        http.authorizeHttpRequests((authz) -> authz.anyRequest().authenticated()).oauth2Login();
        return http.build();
    }


    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration
                .setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://localhost", "http://localhost:8080"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"));
        configuration.setAllowCredentials(false);

        // the below three lines will add the relevant CORS response headers
        configuration.addAllowedOrigin("*");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    
    @Bean
    public RequestCache refererRequestCache() {
        return new HttpSessionRequestCache() {
            @Override
            public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
                String referrer = request.getHeader("referer");
                if (referrer != null) {
                    request.getSession().setAttribute("SPRING_SECURITY_SAVED_REQUEST", new SimpleSavedRequest(referrer));
                }
            }
        };
    }
}

Below is the CORS Filter

@Slf4j
public class CORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String check = "xsrf-token,X-Total-Results,Authorization";

        response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
        System.err.println(request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, FETCH");
        response.setHeader("Access-Control-Max-Age", "3600"); //
        response.setHeader("Access-Control-Allow-Headers",
                "Content-Type, Accept, X-Requested-With, remember-me, Authorization");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Expose-Headers", check);

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            log.warn("Request get method call status SC_OK.");
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            log.warn("Request get method not work chain start.");
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

I noticed that JSESSIONID is missing while invoking the url from react app while the same is present while invoking from standalone browser. Also invoking in a pop up window oauth2 flow is getting completed. I am wondering what wrong with react without pop-up



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source