How to fix CORS error blocked by CORS policy in Spring Boot
The browser blocks requests from my frontend app to my Spring Boot REST API:
Access to XMLHttpRequest at 'http://localhost:8080/api/users'
from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
The API works fine when called from Postman, but fails in the browser. How do I configure CORS in Spring Boot?
Solution
Spring Boot blocks cross-origin requests by default for security reasons. For a quick fix on a specific controller, add the @CrossOrigin annotation:
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "http://localhost:3000")
public class UserController {
@GetMapping
public List<User> getUsers() {
return userService.findAll();
}
}
For a global configuration that applies to all controllers, implement WebMvcConfigurer:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
Alternative #1
If you use Spring Security, the CORS configuration from WebMvcConfigurer may be ignored because Spring Security's filter chain intercepts requests before they reach the MVC layer. You must also enable CORS in your security configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(csrf -> csrf.disable())
// ... rest of your security config
;
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Alternative #2
For development environments, you can proxy API requests through the frontend dev server instead of configuring CORS on the backend. With Next.js, add a rewrite rule in next.config.js:
// next.config.js
const nextConfig = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://localhost:8080/api/:path*',
},
]
},
}
Requests from the browser go to http://localhost:3000/api/users, and Next.js proxies them to http://localhost:8080/api/users server-side. Since the request originates from the same origin as far as the browser is concerned, no CORS headers are needed.