Résoudre les erreurs CORS sur un Webhook n8n : appeler un workflow depuis le navigateur
Par Clément Lacaille (Tech-Bharat) · Publié le 22 septembre 2026 · 6 min de lecture · notre méthode
Bundle FlowKit Complet — 269 €
12 workflows n8n prêts à importer, guide en français, garantie 14 jours
Le scénario est classique : vous construisez un node Webhook dans n8n, vous le testez avec curl ou dans Postman, tout répond parfaitement. Puis vous branchez un simple fetch() depuis le JavaScript de votre site, et la console du navigateur affiche une ligne rouge sans appel : « Access to fetch at '...' from origin '...' has been blocked by CORS policy ». Rien n'a changé côté n8n entre les deux tests — c'est le navigateur qui applique une vérification que curl ignore purement et simplement. Ce guide explique ce que fait réellement CORS, pourquoi le réglage évident du node Webhook ne suffit pas toujours, et le pattern qui fonctionne dans tous les cas, y compris sur n8n Cloud.
Ce que fait vraiment une erreur CORS
CORS (Cross-Origin Resource Sharing) n'est pas une fonctionnalité de n8n : c'est une règle de sécurité imposée par tous les navigateurs modernes. Par défaut, une page chargée depuis https://monsite.fr n'a pas le droit de lire la réponse d'une requête envoyée vers un autre domaine (votre instance n8n, https://n8n.monentreprise.com) — sauf si ce second domaine répond explicitement qu'il l'autorise, via l'en-tête Access-Control-Allow-Origin.
Deux cas se présentent :
- Requête simple (GET sans en-tête particulier, ou POST avec
Content-Type: text/plain) : le navigateur envoie directement la requête, puis vérifie l'en-tête de la réponse avant de la transmettre à votre code. - Requête « à préflight » (c'est le cas de presque tous les appels à un webhook n8n : POST avec
Content-Type: application/json, ou un en-tête d'authentification personnalisé) : le navigateur envoie d'abord une requête OPTIONS pour demander l'autorisation, et n'envoie la vraie requête que si la réponse à ce préflight contient les bons en-têtes.
C'est ce deuxième cas qui piège la majorité des intégrations n8n : le webhook lui-même est irréprochable, mais rien ne répond correctement à la requête OPTIONS envoyée juste avant.
L'option Allowed Origins (CORS) du node Webhook, et sa limite
Le node Webhook expose, dans l'onglet Options, un réglage Allowed Origins (CORS) : une liste de domaines séparés par des virgules, ou * par défaut pour tout autoriser. C'est le premier réflexe, et il est indispensable — mais il ne raconte qu'une partie de l'histoire. Ce réglage (comme les en-têtes personnalisés que vous ajoutez via un node Respond to Webhook) s'applique à la réponse de votre requête réelle. De nombreux retours de la communauté n8n documentent des cas où la requête OPTIONS de préflight n'obtient pas ces mêmes en-têtes, parce qu'aucun node de votre workflow n'est configuré pour y répondre : votre webhook n'écoute que sur POST, et n8n ne sait pas quoi faire d'une requête OPTIONS sur ce même chemin.
Le symptôme est net : l'erreur CORS mentionne votre origine correctement configurée, l'appel fonctionne parfaitement en curl, mais le navigateur bloque quand même — et l'onglet Réseau des outils de développement montre une requête OPTIONS qui échoue ou renvoie un 404, jamais suivie de la requête POST.
Solution niveau instance (self-hosted) : les variables N8N_CORS_*
Si vous gérez vous-même votre instance n8n (Docker, VM, PM2...), la solution la plus propre se règle une fois pour toutes, en dehors de l'éditeur de workflows. Deux variables d'environnement :
| Variable | Rôle | Valeur recommandée en production |
|---|---|---|
N8N_CORS_ENABLED |
Active le middleware CORS intégré à n8n, qui répond correctement aux requêtes OPTIONS avant même qu'elles n'atteignent vos nodes | true |
N8N_CORS_ALLOW_ORIGIN |
Liste des origines autorisées (séparées par des virgules) | Votre domaine exact, jamais * |
Ajoutez ces deux lignes à votre fichier .env ou à la configuration de votre conteneur, redémarrez l'instance, et le préflight OPTIONS est géré au niveau du serveur HTTP de n8n lui-même — plus besoin de node dédié pour chaque webhook. C'est l'équivalent, côté n8n, des variables d'environnement que vous configurez déjà pour vos credentials ou vos limites de taille de payload.
Solution universelle (n8n Cloud ou instance mutualisée) : un node OPTIONS dédié
Sur n8n Cloud, vous ne contrôlez pas les variables d'environnement de l'instance. Le contournement qui fonctionne à coup sûr, quelle que soit votre offre, consiste à dupliquer votre point d'entrée :
- Ajoutez un second node Webhook, sur le même chemin (
path) que votre webhook principal, mais avec la méthode HTTP réglée surOPTIONS. - Branchez-le directement sur un node Respond to Webhook qui renvoie un code
204(pas de contenu) avec trois en-têtes :Access-Control-Allow-Origin(votre domaine),Access-Control-Allow-Methods(POST, OPTIONS) etAccess-Control-Allow-Headers(Content-Type, plus tout en-tête personnalisé que votre appel envoie, comme un jeton d'API). - Laissez votre webhook principal (
POST) inchangé, avec son propreAllowed Origins (CORS)renseigné en cohérence.
Le navigateur envoie l'OPTIONS, tombe sur ce node dédié, obtient une réponse explicite en quelques millisecondes, puis envoie la vraie requête POST qui, elle, s'exécute normalement dans votre logique métier.
Une alternative plus robuste : ne pas exposer le webhook au navigateur
CORS n'est pas un problème à contourner à tout prix : c'est un signal. Si votre webhook doit rester réservé à votre propre application, la vraie question est de savoir si un appel direct depuis le navigateur est la bonne architecture. Une étude empirique de référence sur le sujet, celle de Chen, Jiang, Duan, Wan, Chen, Paxson et Yang, « We Still Don't Have Secure Cross-Domain Requests: an Empirical Study of CORS » (USENIX Security Symposium, 2018), a mesuré qu'une part significative des sites qui configurent CORS le font de façon trop permissive — origine reflétée sans validation, association avec des cookies d'authentification — ouvrant la porte à des requêtes forgées depuis un site tiers malveillant. La leçon pratique : ne laissez jamais Allowed Origins à * sur un webhook qui écrit des données ou déclenche une action, et évitez d'y associer des credentials sensibles.
Quand c'est possible, la solution la plus sûre reste de faire transiter l'appel par votre propre backend (une fonction serverless, une route API de votre framework) qui relaie ensuite la requête vers n8n côté serveur — sans jamais exposer directement l'URL du webhook au navigateur. Le problème de CORS disparaît purement et simplement, puisque l'appel navigateur → votre serveur reste sur la même origine, et l'appel serveur → n8n n'est jamais soumis à cette politique. C'est aussi l'occasion d'ajouter une couche d'authentification et de vérification de signature que le navigateur, par nature, ne peut jamais garder secrète.
Le cas particulier du Chat Trigger
Si votre besoin est un widget de chat plutôt qu'un formulaire ou une API métier, ne réinventez pas ce mécanisme à la main : le node Chat Trigger et le widget officiel @n8n/chat gèrent nativement leur propre réglage Allowed Origins, avec un comportement plus prévisible sur le préflight que le node Webhook générique. Notre guide d'intégration d'un widget de chat IA sur un site détaille cette configuration spécifique — les patterns de cet article s'appliquent surtout au cas d'un webhook « classique » appelé depuis votre propre code (formulaire, application, API).
C'est exactement le cas d'usage du workflow API question-réponse RAG du Pack Assistant RAG (119 €) : un endpoint n8n pensé pour être appelé depuis une application tierce, avec l'authentification et le format de réponse déjà réglés — il ne reste qu'à brancher les en-têtes CORS sur votre propre domaine.
Ce qu'il faut retenir
Une erreur CORS sur un webhook n8n qui fonctionne par ailleurs très bien signale presque toujours le même angle mort : la requête de préflight OPTIONS, pas la requête réelle. Sur une instance self-hosted, N8N_CORS_ENABLED et N8N_CORS_ALLOW_ORIGIN règlent le problème une fois pour toutes au niveau du serveur. Sur n8n Cloud, un second node Webhook dédié à la méthode OPTIONS reproduit le même comportement à la main. Et si le webhook expose une action sensible, la meilleure protection contre une mauvaise configuration CORS reste de ne jamais l'exposer directement au navigateur — un relais côté serveur règle à la fois le problème technique et le risque de sécurité qui va avec.
FAQ
Questions fréquentes
Pourquoi mon webhook n8n fonctionne avec Postman ou curl mais pas depuis mon site ?
Parce que la politique CORS (Cross-Origin Resource Sharing) est une protection appliquée par le navigateur, pas par le serveur. curl, Postman ou un appel serveur à serveur n'exécutent pas cette vérification : ils envoient la requête et lisent la réponse, point final. Un navigateur, lui, vérifie d'abord que le serveur autorise explicitement l'origine (le domaine) qui a chargé la page avant de laisser votre code JavaScript lire la réponse — et pour une requête non triviale (JSON, en-têtes personnalisés), il envoie même une requête préalable OPTIONS pour le demander.
Le réglage "Allowed Origins (CORS)" du node Webhook suffit-il à régler le problème ?
Il couvre la réponse à votre requête réelle (GET, POST...), mais de nombreux retours de la communauté n8n signalent qu'il ne suffit pas toujours à satisfaire la requête de pré-vol OPTIONS envoyée par le navigateur avant celle-ci, en particulier avec un Content-Type application/json ou des en-têtes personnalisés. Si l'erreur CORS persiste alors que l'origine est bien renseignée, c'est presque toujours ce préflight qui échoue, pas la requête elle-même.
Comment activer CORS au niveau de l'instance sur n8n self-hosted ?
Deux variables d'environnement à définir au démarrage du conteneur ou du process : N8N_CORS_ENABLED=true pour activer le middleware CORS intégré, et N8N_CORS_ALLOW_ORIGIN=https://votredomaine.fr pour restreindre les origines acceptées (la valeur par défaut, *, accepte n'importe quel site). Ces variables agissent avant même que la requête n'atteigne vos nodes, ce qui règle aussi bien la requête réelle que le préflight OPTIONS.
Et sur n8n Cloud, où je ne peux pas définir ces variables d'environnement ?
Le contournement fiable consiste à ajouter un second node Webhook sur le même chemin, configuré sur la méthode OPTIONS, qui répond immédiatement via un node Respond to Webhook avec les en-têtes Access-Control-Allow-Origin, Access-Control-Allow-Methods et Access-Control-Allow-Headers et un code 204. Le navigateur obtient ainsi une réponse explicite à son préflight avant d'envoyer la requête réelle sur le node POST classique.