Comment corriger les erreurs CORS (et pourquoi elles surviennent)
Une erreur CORS signifie que votre page web a tenté de lire une réponse provenant d'une autre origine (un autre domaine, port ou protocole), et que ce serveur n'a pas envoyé les en-têtes indiquant que c'est autorisé. Les navigateurs bloquent la réponse pour protéger les utilisateurs. Vous la corrigez sur le serveur, en renvoyant un en-tête Access-Control-Allow-Origin pour l'origine de votre site et en gérant les requêtes preflight OPTIONS, ou vous l'évitez en envoyant la requête via votre propre backend, sur la même origine.
C'est l'une des erreurs les plus déroutantes du développement web, car la requête atteint souvent le serveur sans problème. Ce guide explique ce qui se passe et comment corriger chaque variante.
Ce qu'on entend par « origine »
Une origine est la combinaison du protocole, du domaine et du port :
| URL | Origine |
|---|---|
https://monapp.com/dashboard | https://monapp.com |
https://api.monapp.com/users | https://api.monapp.com (sous-domaine différent, donc origine différente) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (port différent, donc origine différente) |
Les navigateurs appliquent la politique de même origine : le JavaScript d'une page peut lire librement les réponses de sa propre origine, mais pas celles des autres. CORS (Cross-Origin Resource Sharing, partage des ressources entre origines) est le mécanisme par lequel un serveur donne son accord : « les réponses de ce serveur peuvent être lues par des pages provenant de ces origines ».
Deux conséquences surprennent souvent :
- La requête atteint souvent le serveur. CORS empêche généralement votre code de lire la réponse, pas le serveur de recevoir la requête. Un POST peut avoir été enregistré même si vous avez vu une erreur.
- Seuls les navigateurs appliquent CORS. curl, Postman et le code côté serveur l'ignorent totalement. C'est pourquoi « ça marche dans Postman » ne vous dit rien sur CORS.
Étape 1 : Lire l'erreur exacte
Ouvrez les outils de développement (clic droit → Inspecter), allez dans la Console et lisez le message complet. La formulation de Chrome indique le problème :
| Le message contient | Ce qui ne va pas |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Le serveur n'a pas envoyé l'en-tête du tout, ou la requête a échoué avant d'atteindre votre code CORS (par exemple une 404 ou une 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Le serveur autorise une autre origine que la vôtre |
Response to preflight request doesn't pass access control check | La requête OPTIONS de preflight a échoué |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Vous envoyez des cookies, et le serveur a répondu avec * |
Request header field authorization is not allowed | Le serveur n'a pas listé cet en-tête dans Access-Control-Allow-Headers |
Ouvrez ensuite l'onglet Réseau, repérez la requête en échec (et toute requête OPTIONS qui la précède), et regardez son code de statut et ses en-têtes de réponse.
Vérifiez d'abord le code de statut. Beaucoup d'« erreurs CORS » sont en réalité une erreur serveur déguisée. Si le serveur plante ou renvoie une 404, sa réponse d'erreur n'a souvent pas d'en-têtes CORS, donc le navigateur signale CORS au lieu du vrai problème. Corrigez la 500 ou la 404, et l'erreur CORS peut disparaître.
Étape 2 : Décider si vous devez appeler cette API depuis le navigateur
Avant d'ajouter des en-têtes, posez-vous la question : le navigateur doit-il appeler directement cette API ?
- Une API tierce qui nécessite une clé secrète (OpenAI, clé secrète Stripe, la plupart des services d'e-mail) ne doit jamais être appelée depuis le navigateur. La clé serait visible par chaque visiteur. Appelez-la depuis votre backend : le problème CORS disparaît, car les requêtes serveur à serveur ne sont pas soumises à CORS. Voir comment protéger vos clés d'API.
- Une API tierce que vous ne contrôlez pas et qui n'envoie pas d'en-têtes CORS ne peut pas être corrigée de votre côté. Appelez-la depuis votre backend.
- Votre propre API peut être corrigée en la configurant correctement. Voir la suite.
Étape 3 : Corriger sur votre serveur
Le serveur doit ajouter les bons en-têtes à ses réponses, y compris les réponses d'erreur.
Pour la requête réelle, envoyez :
Access-Control-Allow-Origin: https://monapp.com(l'origine exacte de votre frontend, sans barre oblique finale)Vary: Origin, si la valeur dépend de l'origine qui a fait la demande
Pour la requête OPTIONS de preflight, répondez avec un statut de succès (200 ou 204) et :
Access-Control-Allow-Origin: https://monapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(chaque en-tête personnalisé que vous envoyez)- Facultatif :
Access-Control-Max-Age: 600, pour que le navigateur mette le preflight en cache un moment
La plupart des frameworks disposent d'un paquet ou d'un réglage qui fait cela. Dans Express, le paquet cors ; dans FastAPI, CORSMiddleware ; dans ASP.NET Core, AddCors ; dans Spring, @CrossOrigin ou une configuration CORS. Une configuration typique avec Express :
import cors from "cors";
app.use(cors({
origin: ["https://monapp.com", "http://localhost:5173"],
credentials: true,
}));
Placez la gestion de CORS avant vos routes et votre authentification, pour que les requêtes preflight (qui ne transportent pas de connexion) ne soient pas rejetées avec une 401.
Avec un générateur d'IA, décrivez précisément la configuration :
Le frontend sur
https://monapp.comappelle l'API surhttps://api.monapp.comet reçoit « Response to preflight request doesn't pass access control check ». Configure CORS sur l'API pour autoriser exactementhttps://monapp.comet l'origine de l'aperçu, autorise GET, POST, PATCH, DELETE avec les en-têtes Content-Type et Authorization, traite OPTIONS avant l'authentification, et inclus aussi les en-têtes CORS dans les réponses d'erreur.
Étape 4 : Gérer les cookies et les identifiants
Si votre frontend envoie des cookies (par exemple une session de connexion) à une autre origine, les deux côtés doivent être d'accord :
- Le frontend définit
credentials: "include"surfetch, ouwithCredentials: trueavec axios. - Le serveur envoie
Access-Control-Allow-Credentials: true. - L'en-tête
Access-Control-Allow-Origindu serveur doit être l'origine exacte, et non*.
Les cookies inter-sites nécessitent aussi SameSite=None; Secure sur le cookie, et certains navigateurs restreignent davantage les cookies tiers. C'est une raison de plus de privilégier l'approche de l'étape 5.
Étape 5 : Éviter CORS avec une configuration de même origine
Souvent, la solution la plus propre consiste à ne faire aucune requête inter-origines. Servez l'API depuis la même origine que la page, par exemple à https://monapp.com/api/... :
- En développement, la plupart des serveurs de développement peuvent faire office de proxy. L'option
server.proxyde Vite peut transmettre/apià votre backend sur un autre port, de sorte que le navigateur ne communique qu'avec une seule origine. - En production, routez
/apivers le backend via les réglages de réécriture ou de proxy de votre hébergeur, ou servez le frontend et l'API depuis un même serveur.
Le frontend appelle alors un chemin relatif comme fetch("/api/orders"). Il n'y a plus de requête inter-origines, plus de preflight entre origines, et plus de problèmes de cookies. Vous n'avez pas non plus à coder en dur un domaine d'API qui diffère entre l'aperçu et la production.
Modifie le frontend pour appeler le backend avec des chemins relatifs /api au lieu d'une URL complète, et configure un proxy de développement pour que /api soit transmis au serveur d'API. Supprime ensuite les réglages CORS dont nous n'avons plus besoin.
Ce qu'il ne faut pas faire
mode: "no-cors"dansfetch. Cela ne contourne rien ; cela donne à votre code une réponse vide et illisible.- Les extensions de navigateur qui désactivent CORS. Elles ne modifient que votre navigateur. Chaque visiteur verra toujours l'erreur.
- Les services publics de « proxy CORS » pour de vraies applications. Ils peuvent lire et modifier tout ce qui passe par eux, et ils tombent en panne.
Access-Control-Allow-Origin: *sur une API qui utilise des connexions. Cela ne fonctionne pas avec les identifiants de toute façon, et c'est le mauvais choix par défaut pour des données privées.- Renvoyer en écho n'importe quelle en-tête
Originavec les identifiants autorisés. Cela permet à n'importe quel site web de faire des requêtes authentifiées au nom de vos utilisateurs. Utilisez une liste d'autorisation.
Causes fréquentes dans les applications créées avec l'IA
| Situation | Correction |
|---|---|
| Le frontend appelle une API tierce avec une clé secrète | Déplacer l'appel vers le backend |
| Fonctionne dans l'aperçu, échoue sur le domaine publié | Ajouter les origines publiées et du domaine personnalisé à la liste d'autorisation, ou utiliser des chemins /api relatifs |
| Erreur uniquement sur POST, PUT ou DELETE | Preflight non géré ; ajouter la gestion d'OPTIONS et les en-têtes autorisés |
| L'erreur est apparue après l'ajout d'une connexion | Les identifiants exigent une origine exacte et Allow-Credentials |
| « Erreur CORS » mais l'onglet Réseau affiche 500 | Corriger d'abord l'erreur serveur |
URL de l'API codée en dur sur localhost | Utiliser des chemins relatifs ou un réglage par environnement |
CORS dans Mythex
Lorsqu'un projet Mythex contient un site web et un serveur d'API, les deux tournent comme services dans le même projet, et vous pouvez basculer entre eux dans l'aperçu. Demander à l'agent que le frontend appelle le backend via un chemin /api relatif, transmis en développement, évite la plupart des problèmes CORS. Si vous avez vraiment besoin d'appels inter-origines, donnez à l'agent l'erreur exacte de la console et les origines concernées. Vérifiez aussi le résultat sur l'application publiée, car son adresse diffère de celle de l'aperçu. Voir Applications multi-services et Backends d'API dans la documentation, ainsi que nos guides sur le débogage d'une application créée avec l'IA et frontend vs backend.
Checklist CORS
- Lu le message complet de la console et le code de statut de la requête en échec
- Écarté une 404 ou une 500 cachée
- APIs à clé secrète appelées depuis le backend, et non depuis le navigateur
- Le serveur envoie
Access-Control-Allow-Originavec les origines autorisées exactes - Le preflight
OPTIONSreçoit les méthodes et en-têtes autorisés, avant l'authentification - Les en-têtes CORS sont présents aussi dans les réponses d'erreur
- Identifiants : origine exacte,
Allow-Credentials: true, réglages de cookies corrects - Origines de l'aperçu, du site publié et du domaine personnalisé toutes couvertes, ou chemins
/apirelatifs utilisés - Aucun raccourci
no-cors, proxy public ou origine renvoyée en écho
Questions
Que signifie une erreur CORS ?
Votre page, chargée depuis une origine, a tenté de lire une réponse provenant d'une autre origine, et le serveur de cette origine n'incluait pas les en-têtes qui l'autorisent. Le navigateur empêche votre code de lire la réponse. La correction se fait sur le serveur, ou dans la façon dont la requête est routée, et non dans le code frontend.
Puis-je corriger une erreur CORS depuis le frontend ?
Pas vraiment. Des réglages comme mode: 'no-cors' ne font que masquer la réponse à votre code. Vous corrigez le problème en faisant envoyer au serveur le bon en-tête Access-Control-Allow-Origin, ou en appelant l'API depuis votre propre backend ou un proxy de même origine.
Access-Control-Allow-Origin: * est-il sûr ?
C'est acceptable pour des données publiques que n'importe qui peut lire, comme une API publique sans connexion. Cela ne peut pas être utilisé avec des cookies ni d'autres identifiants, et pour les API privées vous devez lister les origines exactes autorisées.
Pourquoi ma requête fonctionne-t-elle dans Postman ou curl mais pas dans le navigateur ?
CORS n'est appliqué que par les navigateurs. Des outils comme Postman et curl ne l'appliquent pas, donc une requête peut réussir là-bas et être tout de même bloquée lorsque le JavaScript de la page la fait.
Qu'est-ce qu'une requête preflight ?
Pour les requêtes qui ne sont pas simples, comme un POST en JSON ou une requête avec un en-tête Authorization, le navigateur envoie d'abord une requête OPTIONS pour demander au serveur quelles méthodes et quels en-têtes sont autorisés. Si cette requête OPTIONS échoue ou ne contient pas les bons en-têtes, la requête réelle n'est jamais envoyée.