Spring Boot
Cross-Origin
CORS
Web Development
Java

add multiple cross origin urls in spring boot

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a Spring Boot API needs to accept requests from several frontend origins, the solution is to list those origins explicitly in your CORS configuration. You can do that at the controller level with @CrossOrigin or globally with a WebMvcConfigurer, depending on whether the rule should apply to one endpoint or the whole application.

What Multiple Origins Mean in CORS

Browsers enforce CORS, not Spring Boot. When a frontend at one origin tries to call an API at another origin, the browser checks the server's CORS response headers to decide whether the request is allowed.

An origin is the combination of scheme, host, and port. That means these count as different origins:

  • 'https://app.example.com'
  • 'https://admin.example.com'
  • 'http://localhost:3000'

If your API should accept requests from several of them, each allowed origin needs to be configured intentionally.

That explicit list is important for both security and debugging. When an origin is missing, the browser error is often vague, so a deliberate allow-list makes misconfigurations easier to spot.

Controller-Level Configuration

For a small API or a single endpoint, @CrossOrigin is the simplest option:

java
1import org.springframework.web.bind.annotation.CrossOrigin;
2import org.springframework.web.bind.annotation.GetMapping;
3import org.springframework.web.bind.annotation.RestController;
4
5@RestController
6@CrossOrigin(origins = {
7    "http://localhost:3000",
8    "https://app.example.com",
9    "https://admin.example.com"
10})
11public class GreetingController {
12
13    @GetMapping("/api/greeting")
14    public String greeting() {
15        return "hello";
16    }
17}

This works well when only one controller needs those origins. It becomes harder to manage when the same list must be repeated across many endpoints.

Global CORS Configuration

For application-wide rules, configure CORS centrally:

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.web.servlet.config.annotation.CorsRegistry;
3import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4
5@Configuration
6public class CorsConfig implements WebMvcConfigurer {
7
8    @Override
9    public void addCorsMappings(CorsRegistry registry) {
10        registry.addMapping("/api/**")
11            .allowedOrigins(
12                "http://localhost:3000",
13                "https://app.example.com",
14                "https://admin.example.com"
15            )
16            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
17            .allowedHeaders("*")
18            .allowCredentials(true);
19    }
20}

This approach is usually better for consistency. One config class controls the allowed origins for all matching routes, so there is less duplication and less chance of forgetting one endpoint.

When to Use allowedOriginPatterns

Sometimes the allowed origins are not fixed values. For example, preview environments may use dynamic subdomains. In those cases, allowedOriginPatterns can be more useful than allowedOrigins:

java
registry.addMapping("/api/**")
    .allowedOriginPatterns("https://*.preview.example.com")
    .allowedMethods("GET", "POST");

Use this carefully. Pattern-based rules are broader than exact-origin rules, so they should be limited to well-understood domain spaces.

Spring Security Can Override You

A common source of confusion is configuring CORS in Spring MVC while Spring Security is also active. If security is enabled, make sure CORS is enabled there too, or the browser may still reject requests even though the MVC configuration looks correct.

A minimal security setup looks like this:

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.security.config.Customizer;
3import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4import org.springframework.security.web.SecurityFilterChain;
5
6@Bean
7SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
8    http
9        .cors(Customizer.withDefaults())
10        .csrf(csrf -> csrf.disable());
11
12    return http.build();
13}

Without that, preflight requests can fail before your controller logic is even reached.

Common Pitfalls

The most common mistake is forgetting that origins include the port. Allowing https://app.example.com does not automatically allow https://app.example.com:8443.

Another issue is using "*" together with credentials. Browsers do not allow wildcard origins when allowCredentials(true) is in play.

Teams also duplicate CORS config in multiple places and then debug the wrong class. Pick one clear source of truth whenever possible.

Summary

  • Add multiple origins in Spring Boot by listing them explicitly in @CrossOrigin or allowedOrigins.
  • Use controller-level configuration for narrow cases and global config for shared API rules.
  • Reach for allowedOriginPatterns only when exact origins are not practical.
  • If Spring Security is enabled, turn on CORS there as well.
  • Remember that scheme, host, and port all matter when matching an origin.

Course illustration
Course illustration

All Rights Reserved.