Cors Error when using CorsFilter and spring security
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
CORS errors in a Spring application often happen not because CORS is completely missing, but because Spring Security and the CORS configuration disagree about who should handle preflight and cross-origin headers. The clean solution is usually to let Spring Security integrate with a single clear CORS configuration source instead of layering several partial fixes on top of each other.
Why CORS Fails with Spring Security
A browser sends preflight OPTIONS requests before certain cross-origin calls. If that request is blocked by security before the CORS headers are added, the browser reports a CORS failure even though the real backend problem is filter-chain ordering or missing security integration.
Typical symptoms include:
- '
403 ForbiddenonOPTIONS' - missing
Access-Control-Allow-Origin - preflight succeeds in Postman but fails in the browser
- duplicate or conflicting CORS headers
Prefer Security-Integrated CORS Configuration
In modern Spring Security setups, the usual pattern is to register a CorsConfigurationSource and enable http.cors() in the security chain.
This approach lets Spring Security participate correctly instead of accidentally rejecting requests before CORS handling runs.
Avoid Double Configuration Unless You Mean It
A common anti-pattern is combining:
- a standalone
CorsFilter - controller-level
@CrossOrigin - custom headers from another filter
- Spring Security CORS integration
all at the same time.
That can produce confusing behavior because different parts of the stack may add different headers or run in different order.
Usually one consistent configuration path is better than several overlapping ones.
Preflight Requests Must Be Allowed
If the browser sends OPTIONS and the backend blocks it, the real application request never happens.
That is why your security rules must allow the preflight path to be processed correctly. Sometimes the CORS configuration is fine, but authorization rules are still too strict.
The security chain and CORS chain have to cooperate.
allowedOrigins and Credentials Matter
If allowCredentials(true) is used, a wildcard origin such as * is not appropriate in the typical credentialed browser flow. That mismatch often leads to confusing browser-side failures.
So if cookies or authorization headers are involved, use explicit allowed origins instead of a blanket wildcard.
How to Debug It
A useful debugging checklist is:
- inspect the browser Network tab
- look at the
OPTIONSpreflight response - check whether CORS headers are present there
- confirm whether Spring Security returned
401or403before CORS handling completed - reduce configuration to one CORS mechanism instead of many
The browser error message alone often hides which backend response actually caused the failure.
Common Pitfalls
The most common mistake is adding a CorsFilter but forgetting that Spring Security can still block the request before the browser sees the right headers.
Another issue is configuring CORS in multiple places and then getting conflicting behavior that is hard to reason about.
People also allow credentials while using overly broad or incompatible origin settings.
Finally, do not debug CORS only with Postman. CORS is enforced by browsers, so the browser network trace is the most relevant evidence.
Summary
- CORS problems with Spring Security are often filter-chain coordination problems.
- A
CorsConfigurationSourceplushttp.cors()is usually the cleanest setup. - Preflight
OPTIONSrequests must be allowed to pass correctly. - Avoid overlapping CORS configuration in several places unless you need it intentionally.
- Debug in the browser network tab, not only with non-browser clients.

