TL;DR
The bug is usually the preflight (OPTIONS), not your fetch call or the client library.
Access-Control-Allow-Origin: * and credentials: 'include' never work together.
Echo an exact origin from an allowlist — not a wildcard — when the SPA and API sit on different hosts.
Your SPA lives on https://app.example.com. Your API lives on https://api.example.com. You open DevTools, hit a button, and get a red CORS error. The first instinct is to blame axios, the SDK, or “browser fetch being weird.”
Pause. Cross-origin requests that are not simple GETs almost always send an OPTIONS preflight first. If that preflight fails, the real request never leaves the browser — and nothing you change in the client will fix a missing or wrong response header on the API.
This post is a portable SPA→API CORS recipe: minimal repro, Express and Caddy configs that engineers actually paste, the credentials gotcha, and a failure checklist. No product tour. Just headers that make the
Discussion
Get the discussion rolling
A single comment can start something great.