Skip to content

CORS in Spring Boot — Configuring Cross-Origin with @CrossOrigin Annotation

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about CORS in Spring Boot. We cover key concepts, practical examples, and best practices to help you master this topic.

Spring Boot provides multiple ways to configure CORS: the @CrossOrigin annotation for per-endpoint control, WebMvcConfigurer for global configuration, and WebFlux support for reactive applications.

What You'll Learn

  • Using @CrossOrigin annotation on controllers
  • Global CORS configuration with WebMvcConfigurer
  • CORS for reactive Spring WebFlux

Why It Matters

Spring Boot powers many enterprise Java APIs. Proper CORS configuration enables secure cross-origin access for web frontends while maintaining Spring's security model. DodaTech's enterprise threat management API uses Spring Boot with globally configured CORS.

flowchart TD
    A["Spring Boot API"] --> B{"Configuration approach"}
    B -->|"Annotation"| C["@CrossOrigin on controller"]
    B -->|"Global"| D["WebMvcConfigurer bean"]
    B -->|"Reactive"| E["WebFlux config"]
    C --> F["Works for specific endpoints"]
    D --> G["Works for all endpoints"]
    E --> H["Works for reactive stack"]

Code Examples

// Per-controller @CrossOrigin annotation
@RestController
@RequestMapping("/api/public")
@CrossOrigin(origins = "*")
public class PublicController {

    @GetMapping("/data")
    public Map<String, String> getData() {
        return Map.of("message", "public data");
    }
}

// Specific endpoint with restricted origin
@RestController
@RequestMapping("/api/admin")
public class AdminController {

    @CrossOrigin(origins = "https://admin.example.com")
    @DeleteMapping("/users/{id}")
    public Map<String, String> deleteUser(@PathVariable String id) {
        return Map.of("deleted", id);
    }
}
// Global CORS configuration via WebMvcConfigurer
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins(
                "https://app.example.com",
                "https://admin.example.com"
            )
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("Content-Type", "Authorization")
            .exposedHeaders("X-RateLimit-Remaining")
            .allowCredentials(true)
            .maxAge(3600);
    }
}
// WebFlux reactive CORS configuration
@Configuration
public class ReactiveCorsConfig implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("https://app.example.com")
            .allowedMethods("GET", "POST")
            .allowCredentials(true);
    }
}
# Test Spring Boot CORS
curl -I -H "Origin: https://admin.example.com" \
  http://localhost:8080/api/admin/users/1 \
  -X DELETE | grep -i "access-control"

Common Mistakes

1. Forgetting Spring Security CORS Configuration

Spring Security blocks CORS preflight by default. Add .cors() to the security filter chain.

2. Mixing @CrossOrigin and Global Config

The @CrossOrigin annotation on a method overrides the global config for that method.

3. Not Allowing OPTIONS in Spring Security

Preflight OPTIONS requests must pass through security without authentication.

4. Using Origins with Trailing Slashes

Origins should not have trailing slashes. "https://example.com/" is invalid.

5. Setting allowCredentials to True Without Specific Origins

Same restriction: credentials require specific origins, not wildcard.

Practice Questions

  1. What annotation enables CORS on a Spring controller?
  2. How do you configure global CORS in Spring Boot?
  3. What configuration is needed for Spring Security to work with CORS?
  4. How does WebFlux CORS configuration differ from MVC?
  5. Can you combine @CrossOrigin with WebMvcConfigurer?

Answers:

  1. @CrossOrigin.
  2. Implement WebMvcConfigurer and override addCorsMappings.
  3. Add .cors() to the HttpSecurity configuration.
  4. WebFlux uses CorsRegistry in WebFluxConfigurer instead of WebMvcConfigurer.
  5. Yes. @CrossOrigin on specific methods overrides the global configuration.

Challenge: Build a Spring Boot API with three security tiers (public, authenticated, admin). Implement global CORS for public endpoints and annotation-based CORS for admin endpoints. Configure Spring Security to allow OPTIONS preflight without authentication.

FAQ

Does @CrossOrigin work with Spring Security?

Yes, but Spring Security intercepts all requests before CORS processing. You must add .cors() to your SecurityFilterChain configuration and allow OPTIONS requests to pass without authentication.

Can I use application.properties for CORS configuration?

No. CORS configuration requires Java config. However, you can externalize origin values in application.properties and inject them into your Java configuration.

How do I debug CORS issues in Spring Boot?

Enable Spring's CORS logging: add logging.level.org.springframework.web.cors=DEBUG to application.properties. This logs every CORS decision.

Does Spring Boot CORS support dynamic origins?

Yes. Implement CorsConfigurationSource with a custom origin validation method that reads from a database or configuration service.

What is the default maxAge in Spring Boot CORS?

The default is 1800 seconds (30 minutes). You can override it in your CORS configuration.

Mini Project

Build a Spring Boot API with microservice architecture: a gateway service with CORS configuration, multiple backend services, and a React frontend. Implement Spring Security with JWT authentication and CORS. Add integration tests using TestRestTemplate with custom Origin headers.

What's Next

Explore Flask CORS configuration using flask-cors, then learn NGINX CORS configuration for reverse proxy setups.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro