'problem configuring CORSin spring boot and reactjs

After reading all the MDN docs on CORS, I am trying to fetch resources at a spring boot server at localhost:8080 from a ReactJS app at localhost:3000, yet i cannot get the desired response. here is the spring boot configuration

 ...
 @Override
  protected void configure(HttpSecurity http) throws Exception {
      
    http.cors();
    
    http.authorizeRequests().antMatchers(
        // "/registration**",
        "/js/**", "/css/**", "/img/**", "/api/**", "/webjars/**").permitAll()
        .antMatchers("/calendar", "/calendar-delete", "/calendar-edit", "/calendar-addEvent",
            "/calendar-updateEvent", "/contacts", "/contact-edit", "/jobs/jobs-list", "/job-new",
            "/applicants/applicants-list", "/applicant-new", "/", "/index", "/task-list", "/task-assign",
            "/tasks-pending", "/task-approve", "/task-deny", "/profile", "/upload-avatar", "/users",
            "/settings", "/appsettings", "/changepassword", "/messages", "/message", "/message-new",
            "/message-to", "/h2-console/**")
        .permitAll().antMatchers("/admin/**")
        .hasAuthority("ROLE_ADMIN").antMatchers("/activites/**")
        .hasAnyAuthority("ROLE_ADMIN","ROLE_COLLABORATEUR").and().formLogin().loginProcessingUrl("/api/login").permitAll()
        .and()
        .formLogin().failureHandler(customAuthenticationFailureHandler())
        .and().formLogin().successHandler(successHandler())
        .and()
        .logout()
        .invalidateHttpSession(true).clearAuthentication(true)
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login?logout")
        .permitAll();
    
    http.csrf().disable();
    
  }

@Bean
  public CustomSuccessHandler successHandler() {
      return new CustomSuccessHandler();
  }
....
 @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    
    configuration.setAllowedOrigins(Arrays.asList("*"));    
    configuration.setAllowedMethods(Arrays.asList("GET","POST"));
    configuration.addAllowedHeader("*");
    configuration.setAllowCredentials(false);
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  }

and here is the controller method responsible for handling the request

@GetMapping("/api/plot")
    @ResponseBody
    public List<StatisticBesoin> plot(@RequestParam("date") int year) {
        return this.besoinService.getStatistic(year);
    }

here is the Reactjs Login component, note that after pressing the login button i receive the desired json response and the set-cookies jssid

const Login = (props) => {
    const navig = useNavigate();

    const [userName,setUserName] = useState("");
    const [password,setPassword] = useState("");

    function authenticate(usr,pswrd){
        var data = new URLSearchParams();
        
        data.append('username', usr);
        data.append('password', pswrd);
        
        fetch("http://localhost:8080/api/login",{
            headers:{
                "Content-type": "application/x-www-form-urlencoded",
            },
            method:"post",
            body:data
        }).then(response => response.json()).then(usr => {props.setUser(usr);console.log(usr);navig('/homme')});
    }

    return(
        <div className='wrapper'>
            <div className='login'>
                <div className='header'>Login</div>
                <div className="form-control"><i className="fa fa-user" aria-hidden="true"></i><input onChange={(e)=>setUserName(e.target.value)} name="userName" id="userName" type="text" placeholder="User name" /></div>
                <div className="form-control"><i className="fa fa-lock" aria-hidden="true"></i><input onChange={(e)=>setPassword(e.target.value)} name="userName" id="userPassword" type="password" placeholder="Password" /></div>
                <div className="form-control"><input type="button" value="Login" onClick={()=>authenticate(userName,password)}/></div>
            </div>
        </div>
    )
}

next to the Home page where my issue is:

const Home = (props) => {

    function plot(){
        fetch('http://localhost:8080/api/plot')
        .then(resp => resp)
        .then(t => {console.log(t)})}

    return(
        <div className='wrapper'>
            <input type="button" value="call" onClick={plot}/>
            {props.usr.toString()}
        </div>
    )
} 

the response after pressing the button isز

body: (...)
bodyUsed: false
headers: Headers
[[Prototype]]: Headers
ok: true
redirected: true
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:8080/login"

i tried everything from setting the allowed origins to "*" to setting allow-credentials header in the request to "include" but all in vain. note that i can see the jssid cookie beign sent with the /plot request so i guess i have no problem with authentication. can someone figure out what is the problem please? i think all the ressource of the quetion are available but i will provide any other if needed?



Solution 1:[1]

Provided that this is a local development environment, it's typically sufficient to enable the proxying capabilities of the React development server by enhancing your React app package.json with this attribute:

"proxy": "http://localhost:8080"

Then, make your Ajax requests from your React app to /your/api/path instead of http://localhost:8080/your/api/path and the development webserver will proxy the Ajax requests to the provided address and your browser won't complain about CORS.

You wouldn't need to configure any specific CORS support in the Spring Boot application.

Later, when the application is deployed on a webserver, that's typically no longer an issue because both will be served on the same host and the Ajax requests are then proxied to the backend by a webserver on the host which serves the inbound requests.

Sources

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

Source: Stack Overflow

Solution Source
Solution 1 digitalbreed