Issue
I am at a loss. I am trying to configure CORS
and I have tried just about everything I can find on the internet/Stack overflow.
Requests are working in Postman but not in React using axios.
Here is my function for deleting a user (this works in Postman
but not when triggered in React):
deleteEmployeeById(id) {
// return axios.delete(API_BASE_URL + `employees/${id}`);
var testing = "";
return axios
.delete(API_BASE_URL + `employees/${id}`, {
headers: {
Authorization: `Bearer ${HARDCODED_JWT_TESTING}`,
},
})
.then("yessssss")
.catch((error) => {
console.log("failed to delete emp by id" + error);
});
}
}
I have a SecurityConfig.java file that looks like this:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyUserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO : use this line when i implement bcrypt
// auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
auth.userDetailsService(myUserDetailsService);
}
// TODO : should use this password encoder
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
@Bean
public PasswordEncoder passwordEncoder() {
// TODO : not secure. Use a different encoder. testing only
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// allow users to access "authenticate" page without being authenticated
// all other requests must be authenticated
// stateless tells it to not create a session? Do i need? Not sure yet
// http.csrf().disable().authorizeRequests().antMatchers("/api/authenticate").permitAll().anyRequest()
// .authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues()).and().csrf()
.disable().authorizeRequests().antMatchers("/api/authenticate").permitAll().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
// create bean of type 'authenticationManager'
return super.authenticationManagerBean();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token", "Authorization", "Access-Control-Allow-Origin",
"Access-Control-Allow-Credentials"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
I have no clue which function the error is in, but I assume it is the corsConfigurationSource()
method. However, I see no issue that this shouldn't work. It used to work before I attempted to add security to the app.
AS you can see in that method, I have set all of the allowed methods, I allow all origins, ect, but I still get this error when attempting to delete a user from my database:
Access to XMLHttpRequest at 'http://localhost:8080/api/employees/6151c89ea1b79f789a7a964b' 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.
This DOES work in Postman though. I can Delete a user no problem, it just will not work when triggered from my frontend React app.
It looks like I am allowing everything in CORS
, any idea what else is left to configure??
Solution
Try removing .applyPermitDefaultValues()
call in SecurityConfig
after instantiating CorsConfiguration
. This is basically reseting CORS configuration to the defaults:
- Allow all origins with the special value "*" defined in the CORS spec. This is set only if neither origins nor originPatterns are already set.
- Allow "simple" methods GET, HEAD and POST.
- Allow all headers.
- Set max age to 1800 seconds (30 minutes).
Additionally, call corsConfigurationSource()
method instead of instantiating a new CorsConfiguration
.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource()).and().csrf()
.disable().authorizeRequests().antMatchers("/api/authenticate").permitAll().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
Also, update your CorsConfigurationSource
as follows:
@Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token", "Authorization", "Access-Control-Allow-Origin",
"Access-Control-Allow-Credentials"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Answered By - João Dias