ReviseAlgo Logo

Spring Security

CORS Configuration — Allowing Cross-Origin Requests Safely

Structuring cross-origin sharing configurations for web browsers safely.

Last Updated: June 14, 2026 10 min read

Introduction

Browsers implement the Same-Origin Policy (SOP) to block scripts on one domain from accessing data on another. **CORS (Cross-Origin Resource Sharing)** is a browser mechanism that defines safe rules for allowing cross-domain communication.

Why It Matters

Modern web architectures decouple frontend applications from backend APIs. Without CORS configuration, frontends cannot query backend endpoints. However, a loose CORS configuration (such as allowing all origins via wildcards) opens up users to CSRF attacks or data leakage.

Real-World Analogy

Think of CORS like embassy passport controls. A script from Domain A (a traveler) wants to visit Domain B (the target country). The browser (border guard) stops the script and asks Domain B: "Do you allow travelers from Domain A to enter?" Domain B must return official approval documents (CORS headers) specifying allowed origins, or the browser blocks the script from entering.

Detailed Mechanics

1. CORS Preflight OPTIONS Requests

For requests that modify database data (such as POST with JSON, PUT, or DELETE), browsers send a **Preflight Request** using the OPTIONS method first. This preflight query checks if the target API permits the origin, methods, and headers of the planned call. If the preflight succeeds, the browser sends the actual request.

2. Spring Security CORS Filter

In Spring applications, CORS must be processed at the earliest entry point. Because Spring Security filters execute before MVC controllers, configuring CORS in MVC (e.g. using @CrossOrigin) can fail because Spring Security's authorization filters intercept preflight OPTIONS queries and reject them if they lack authentication headers. CORS should be configured as a servlet Filter inside the security chain.

3. Safe Production Settings

Attribute Wildcard (*) Production Recommendation
allowedOrigins Allows all domains (Insecure) List specific domains (e.g., https://app.company.com)
allowCredentials Cannot be true with origin wildcard Set to true only for trusted origins
maxAge 0 seconds (Browser queries preflight every time) 3600 seconds (Caches preflight, improves speed)

Practical Example

Here is how to configure a CORS filter bean within your Spring Security configuration:

Quick Quiz

Q1: Which HTTP method is executed by web browsers as a preflight CORS validation query?

A) GET

B) POST

C) OPTIONS

D) HEAD

Answer: C — Browsers send OPTIONS requests with CORS metadata headers to confirm path accessibility before firing actual mutating calls.

Q2: Why should CORS be configured in the Spring Security filter chain layer rather than using MVC interceptors?

A) MVC interceptors do not support HTTP OPTIONS checks.

B) Spring Security runs before Spring MVC; security filters would block preflight OPTIONS requests before MVC CORS interceptors can run.

C) Filter configurations run faster than controller mappings.

D) WebMvcConfigurer is deprecated in Spring Boot 3.

Answer: B — Security filters take precedence. Unless CORS is handled early in the filter chain, OPTIONS requests fail authorization audits.

Scenario-Based Challenge

Production Scenario:

You deploy your backend to api.company.com and React frontend to company.com. In your Spring configuration, you declare: configuration.setAllowedOrigins(List.of("https://company.com")). However, the browser blocks request payloads, reporting: "The Access-Control-Allow-Origin header contains multiple values, but only one is allowed". Why did this happen?

View Solution

This happens when CORS has been configured in **multiple places** (e.g., configuring CORS both in Spring Security and also defining a global WebMvcConfigurer or using a cloud proxy/reverse gateway like NGINX that injects the CORS header). The browser receives duplicate Access-Control-Allow-Origin headers and rejects the response. To fix this:

  1. Verify configuration files: ensure CORS is only configured once, preferably in the SecurityFilterChain bean definition.
  2. Check proxy server settings: if NGINX or AWS API Gateway is handling CORS, disable CORS configurations in the Spring Boot application codebase entirely to avoid header duplication.

Interview Questions

1. Conceptual: Why is it invalid to set allowedOrigins to "*" while setting allowCredentials to true?

This is prohibited by W3C browser security specifications. If credential transmission (cookies, Basic Auth, client certs) is permitted, allowing wildcard origins would enable any malicious website to read the victim's private data, defeating Same-Origin Policy protections.

2. Concept: What is the "Access-Control-Max-Age" header and why is it useful?

It specifies the duration (in seconds) that the preflight OPTIONS response can be cached by client browsers. Caching this response prevents the browser from sending redundant OPTIONS requests before every actual API call, reducing latency.

Production Considerations

Do not use wildcards in CORS properties. Set allowedOrigins, allowedMethods, and allowedHeaders explicitly. Configure a reasonable caching limit using maxAge to optimize client performance.