An SPA on `https://app.example.com` calls a Spring Boot API on `https://api.example.com` with `Authorization: Bearer ...` and JSON bodies. Without Spring Security it worked with `@CrossOrigin`; with Spring Security added, every call fails in the browser with a CORS error, yet `curl` with the same token works. Walk through what the browser is sending and what is rejecting it.
An Authorization header and Content-Type: application/json make the request non-simple, so the browser first sends a preflight: an OPTIONS request with Origin and Access-Control-Request-Method, and no credentials at all, because it is the browser asking permission, not the application's request. The security filter chain runs before the dispatcher reaches the controller, so @CrossOrigin is never consulted: the unauthenticated preflight is refused by security, the browser never sends the real request, and the console shows a generic CORS error. curl does not do preflights or enforce CORS, which is why it works. The fix is to put CORS into the security chain with http.cors(...) and a CorsConfigurationSource, so CorsFilter answers the preflight before authentication runs.