Safeguard
Developer Tools•

Why must CORS be handled before Spring Security?

Preflight requests carry no cookies, so Spring Security would reject them as unauthenticated. How to wire CORS first with a CorsConfigurationSource.

Safeguard Security Team
3 min read

CORS must be processed before Spring Security because a browser preflight request does not include cookies such as JSESSIONID. If Spring Security went first, it would see an unauthenticated request and reject it. The simplest fix is to provide a CorsConfigurationSource bean so Spring Security runs the CorsFilter first.

What the preflight is

CORS (cross origin resource sharing) is the browser mechanism that decides whether a page from one origin may read responses from another. For certain requests, the browser first sends an OPTIONS request asking what is allowed. That request deliberately carries no credentials.

If your security rules require authentication for every path, the OPTIONS request fails, the browser reports a CORS error, and the real request is never sent. Developers then often loosen security rules in the wrong place.

The documented approach

The Spring Security reference says Spring Framework has first class CORS support, that CORS must be processed first for the reason above, and that the easiest way to make sure of it is to use the CorsFilter. You integrate the filter by providing a CorsConfigurationSource. It adds that Spring Security configures CORS automatically only if a UrlBasedCorsConfigurationSource instance is present.

The reference example lists explicit allowed origins and methods:

CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));

If you already use Spring MVC's CORS support, the reference says you can omit the source and Spring Security uses the MVC configuration.

Steps

  1. Choose one place to define CORS, either the MVC configuration or a CorsConfigurationSource bean.
  2. List exact origins. Avoid wildcard origins on endpoints that use credentials.
  3. List only the methods and headers you need.
  4. Confirm the security chain enables CORS so the filter runs before authentication.
  5. Test with a real browser call, and with a raw OPTIONS request without cookies.
  6. Do not add a permit all rule for OPTIONS as a workaround.

What CORS does not do

CORS controls which origins can read responses in a browser. It does not authenticate anyone, and it does not stop a forged request from being sent. For that, see does CORS stop CSRF and CORS credentials and wildcard rules.

A worked example

A React app on one origin calls a Spring API on another. Login works in a tool such as curl, but the browser shows a CORS error on every call. The network tab reveals that the OPTIONS preflight returned 401. The API requires authentication for every path, and the preflight carried no cookie, so it was rejected before CORS headers were added.

The cure is not to open the API. It is to define the allowed origin once, make sure the security chain uses it, and confirm the preflight now returns the allow headers while the real request still requires authentication.

Safeguard scans dependencies, produces SBOMs and uses reachability analysis to show which findings your code can actually reach. You can run a free scan at gold.safeguard.sh/scan.

Quick check

Why do I get a CORS error that looks like a 401?

The preflight likely hit your authentication rules without cookies. Make sure the CORS filter runs before Spring Security.

Is permitting all OPTIONS requests a good fix?

It is a workaround that hides the real issue. Configure CORS properly instead.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.