Appels API bloqués par le navigateur (CORS)
```text Access to fetch at 'https://api.exemple.fr/v1/orders' from origin 'https://app.exemple.fr' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present. ```
Détecter
Le front web n'arrive plus à appeler l'API après son déplacement sur un nouveau domaine ; curl fonctionne parfaitement.
Symptômes
Le front web n'arrive plus à appeler l'API après son déplacement sur un nouveau domaine ; curl fonctionne parfaitement.
Environnement
Front sur https://app.exemple.fr, API sur https://api.exemple.fr derrière NGINX, authentification par cookie.
Cause racine
CORS est appliqué par le navigateur. Les requêtes avec cookie ou en-têtes personnalisés déclenchent un preflight OPTIONS ; l'API (ou le proxy) ne renvoie pas les en-têtes attendus, ou renvoie * alors que credentials: include l'interdit.
Diagnostic
curl -si -X OPTIONS https://api.exemple.fr/v1/orders \
-H "Origin: https://app.exemple.fr" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type"
Vérifier : Access-Control-Allow-Origin (origine exacte), Allow-Credentials: true, Allow-Methods, Allow-Headers, et que le preflight répond 204/200 sans authentification.
Solution
Configurer CORS dans l'application (liste blanche d'origines), ou dans NGINX pour la location API, en renvoyant l'origine exacte et Vary: Origin.
Commandes
if ($http_origin = "https://app.exemple.fr") { set $cors $http_origin; }
add_header Access-Control-Allow-Origin $cors always;
add_header Access-Control-Allow-Credentials true always;
add_header Vary Origin always;
Prévention
Liste d'origines en configuration par environnement, tests E2E navigateur (Playwright) en CI, ou même domaine pour front et API (proxy /api).