Случайное имя Webhook не заменяет проверку доступа. Настроим в n8n Header Auth: правильный секрет в заголовке пропустит GET-запрос, отсутствующий или неверный — остановит его до рабочих узлов. Проверим оба результата на отдельном учебном workflow.
Результат инструкции
Соберём схему из трёх узлов. Protected Request проверяет заголовок X-Ezgpt-Key через credentials n8n. При совпадении Build Reply создаёт короткий учебный ответ, а Send Reply возвращает его клиенту. В проверенной версии правильный ключ даёт HTTP 200, неправильный или отсутствующий — 403.
Используем только локальный Test URL, workflow не публикуем. Ключ создаёте вы и храните отдельно от публичного workflow. Никакие базы, документы и внешние API схема не открывает. Header Auth проверяет владение одним общим секретом, но не распределяет права между пользователями и не заменяет HTTPS.
Что понадобится
- Локальный n8n и новый учебный workflow. Проверено на n8n 2.42.4, Webhook 2.1 и Respond to Webhook 1.4.
- Windows PowerShell для генерации секрета и тестового запроса. Пример URL использует порт 5679; подставьте адрес своего n8n.
- Возможность создать Header Auth credential. Настоящие ключи других сервисов для этого примера не нужны.
Установить n8n локально через Docker
Шаг 1. Импортируйте учебную схему
Скачать n8n-webhook-header-auth.json
Создайте отдельный workflow и загрузите JSON через Import from File. В схеме должны быть три узла:
Protected Request → Build Reply → Send Reply
Protected Request — Webhook, Build Reply — Code, Send Reply — Respond to Webhook. Схема неактивна. В ней намеренно нет credentials, их ID и значения ключа: после импорта вы должны выбрать собственный credential. Не меняйте Authentication на None, чтобы убрать предупреждение о недостающем credential.
Шаг 2. Создайте отдельный случайный ключ
Откройте PowerShell и выполните:
$bytes = New-Object byte[] 32
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rng.GetBytes($bytes)
$rng.Dispose()
$secret = ([BitConverter]::ToString($bytes)).Replace("-", "").ToLowerInvariant()
$secret
В окне появится строка из 64 шестнадцатеричных символов, созданная из 32 случайных байт. Сохраните её в своём менеджере секретов и оставьте это окно PowerShell открытым: переменная $secret понадобится для запроса. Это новый секрет только для учебного Webhook, не пароль от n8n и не API-ключ OpenAI.
Не присылайте ключ в чат, не помещайте его в статью, имя credential, URL или скриншот. Вывод в PowerShell тоже чувствителен: не публикуйте снимок этого окна. Если используете уже опубликованный пример ключа, он больше не является секретом.
Шаг 3. Создайте Header Auth credential
В Protected Request выберите Authentication: Header Auth. В выборе credential создайте новый Header Auth credential. Назовите его, например, ezGPT local webhook key. Это название только для вашего удобства, в нём не должно быть самого секрета.
В поле Name укажите X-Ezgpt-Key. В Value вставьте созданную строку без кавычек и лишних пробелов. Сохраните credential и убедитесь, что именно он выбран в Webhook. Name — имя HTTP-заголовка, Value — его секретное значение; это два разных поля.
Для этого примера сервис не выдаёт вам готовый ключ: вы задаёте его сами и затем передаёте тот же секрет в запросе. Credentials хранят настройку проверки, но сами по себе не гарантируют отсутствие секрета в данных входящего запроса и истории выполнения.
Шаг 4. Сверьте параметры Webhook
| Поле | Значение | Проверка |
|---|---|---|
| HTTP Method | GET | Команда должна отправлять GET |
| Path | ezgpt-header-auth-demo | Путь из Test URL |
| Authentication | Header Auth | Выбран созданный credential |
| Respond | Using Respond to Webhook node | Ответ вернёт Send Reply |
Оставьте Options без дополнительных условий. Не заменяйте Header Auth самодельной проверкой $json.headers в Code: тогда запрос уже дошёл бы до workflow. Здесь используется встроенная проверка Webhook до выполнения Build Reply.
Не рассматривайте CORS как замену секрету. Ограничение браузерных источников и проверка значения заголовка решают разные задачи; запрос из curl не становится доверенным из-за настройки CORS.
Шаг 5. Настройте короткий ответ без секрета
В Build Reply выберите Run Once for All Items, JavaScript и оставьте код:
return [{ json: { status: 'ok', test: 'header-auth-demo', action: false } }];
Код не возвращает headers, query, body и credentials. Не используйте для ответа весь вход Webhook: в нём могут оказаться чувствительные значения. В Send Reply задайте Respond With: First Incoming Item, Response Code: 200. В Response Headers добавьте Cache-Control: no-store.
В Settings узлов оставьте On Error: Stop Workflow. Никаких действий с рабочими данными между Webhook и ответом не добавляйте. Статус ok — просто тело учебного ответа; доказательство работы авторизации — пара тестов с правильным и отсутствующим ключом.
Шаг 6. Включите ожидание Test URL
Сохраните workflow, выберите Test URL в Protected Request и нажмите Listen for test event или Execute workflow. Workflow должен ждать входящий запрос. Публиковать его не нужно.
Скопируйте фактический Test URL. В командах ниже используется http://localhost:5679/webhook-test/ezgpt-header-auth-demo. Если у вашего экземпляра другой адрес, замените его. HTTP в этой статье относится только к loopback на собственном компьютере; для передачи ключа через сеть нужен HTTPS с проверкой сертификата.
Test URL работает только при активном ожидании. В проверенном тестовом режиме после успешного запроса нужно снова запустить слушатель. Production URL у неопубликованной схемы не зарегистрирован. Ошибку 404 не нужно исправлять заменой секрета: сначала проверьте URL, метод и ожидание.
Шаг 7. Отправьте правильный ключ
В том же окне PowerShell, где создана переменная $secret, выполните:
$testUrl = "http://localhost:5679/webhook-test/ezgpt-header-auth-demo"
Invoke-RestMethod -Method Get -Uri $testUrl -Headers @{ "X-Ezgpt-Key" = $secret } | ConvertTo-Json
Ожидается HTTP 200 и такой JSON:
{
"status": "ok",
"test": "header-auth-demo",
"action": false
}
В редакторе должны выполниться Build Reply и Send Reply. В ответе не должно быть ключа и входных заголовков. Если открыли новое окно PowerShell, переменная $secret там не задана: не создавайте случайный новый ключ, оставив старый Value в credential, иначе значения не совпадут.
Пример использует встроенный HTTP-клиент PowerShell, поэтому реальный ключ не подставляется в командную строку отдельного процесса curl.exe. Всё равно обращайтесь с переменной и credential как с секретом: не выводите их в общий лог и не используйте на чужом компьютере.
Шаг 8. Проверьте запрос без ключа и с неправильным значением
Убедитесь, что тестовое ожидание активно; после успешного GET включите его заново. Для запроса без ключа выполните:
curl.exe --include --max-time 15 "$testUrl"
В проверенной версии ожидается HTTP 403. Build Reply и Send Reply не должны выполниться для этого запроса. Если тестовый слушатель уже выключен, сначала восстановите ожидание: 404 не проверяет авторизацию.
Для неправильного значения заголовка, при активном ожидании, выполните:
curl.exe --include --max-time 15 "$testUrl" --header "X-Ezgpt-Key: not-the-key"
Ожидается тот же 403 и отсутствие выполнения рабочих узлов. В этих командах --fail не используется, чтобы было удобно увидеть статус отказа. not-the-key — открытая строка для отрицательного теста, не ваш настоящий секрет.
| Запрос | Ожидаемый статус | Рабочие узлы |
|---|---|---|
| Правильный X-Ezgpt-Key | 200 | Выполнились |
| Без секретного заголовка | 403 | Не выполнились |
| Неверное значение ключа | 403 | Не выполнились |
| POST вместо GET | 404 в проверенном тесте | Это ошибка маршрута, не тест ключа |
Шаг 9. Разберите частые несовпадения
Имя заголовка нечувствительно к регистру: x-ezgpt-key с правильным значением в тесте также получил 200. Само значение сравнивается точно: изменение регистра символов ключа привело к 403. Не добавляйте Bearer перед значением, если credential ожидает просто созданную строку.
Authorization: Bearer ... — другой заголовок. Он не заменит X-Ezgpt-Key в этой конфигурации. Ключ в query-параметре тоже не подходит и дополнительно может попасть в историю URL. Используйте только согласованный заголовок, не пробуйте одновременно раскладывать секрет по нескольким полям.
Если корректный на вид запрос получает 403, проверьте, какой credential реально выбран в Webhook, его Name и Value, а также метод и тестовый адрес. Не переключайте Authentication на None для обхода отказа. В отдельном диагностическом workflow редакция подтвердила: с None тот же учебный ответ доступен без ключа.
Шаг 10. Проверьте историю и оставьте схему учебной
Откройте данные успешного выполнения и оцените, где сохраняются входные заголовки. В нашем тестовом экземпляре созданный секрет обнаруживался в данных execution, возвращаемых API. Он не отражался в ответе клиенту, но сохранение в credential не убрало его из истории входящего запроса. Не обещаем, что конкретная настройка n8n автоматически скроет ключ во всех местах.
Используйте отдельный учебный секрет, ограничьте доступ к данным выполнения и настройте хранение и редактирование чувствительных значений по правилам своей системы. Не отправляйте сырые executions в общий чат или внешний AI-сервис. Cache-Control: no-store относится к HTTP-кэшу, а не к базе выполнения n8n.
Верните Authentication: Header Auth и нужный credential. Проверьте ещё раз пару результатов: правильный ключ — 200 с учебным JSON, отсутствующий — 403 без Build Reply. Схему оставьте неопубликованной и остановите тестовое ожидание после работы. Не используйте этот учебный секрет в рабочем сервисе.
Если результат отличается
| Симптом | Что проверить | Действие |
|---|---|---|
| 403 с вашим ключом | Credential, Name и точное Value | Сверить обе стороны, не отключать auth |
| 404 | Test URL, GET и слушатель | Включить ожидание и исправить маршрут |
| Предупреждение о credentials | Выбор после импорта | Создать и выбрать свой credential |
| 200 без ключа | Authentication и совпадение endpoint | Должен быть Header Auth |
| Ключ есть в execution | Доступ, хранение и маскирование | Не рассылать сырые данные |
Перед production
Один общий секрет не даёт индивидуальных прав пользователям и не подписывает тело запроса. Он не защищает от повторной отправки уже известного запроса. Для реальной интеграции отдельно продумайте HTTPS, хранение и замену ключей, ограничения запросов, проверку прав на действие и защиту от повторов. Не используйте IP-адрес или секретный путь вместо проверки доступа.
Если сервис-отправитель использует HMAC-подпись, OAuth или JWT, применяйте его документированный протокол, а не называйте простой Header Auth равноценной заменой. В этой инструкции проверен один фиксированный заголовок и ответ с вымышленными данными; production, proxy и полный аудит безопасности не выполнялись.
Что проверено редакцией
17 октября 2026 года схема проверена на n8n 2.42.4 в отдельном Docker-экземпляре реальными запросами к Test Webhook. Все 16 проверок прошли: правильный ключ, имя заголовка строчными буквами, дополнительный несвязанный заголовок; отсутствие ключа, неверное и пустое значение, другое имя заголовка, ключ только в query, только в Bearer, изменённый регистр ключа и неверно выбранный credential. Подтверждены 200 с точным учебным JSON для правильных запросов и 403 без запуска Build Reply для отказов. Проверены 404 без слушателя, при неверном методе, повторе после успешного теста и у неактивного Production URL. Отдельный диагностический workflow с Authentication None подтвердил доступ без ключа. Публичная схема использовалась с привязкой созданных локально credentials; секретов в скачиваемом workflow нет. В данных успешных executions секрет обнаруживался, в ответе клиенту отсутствовал; сохранённые JSON-отчёты очищены от значения. Настройки сверены с официальной документацией и кодом Webhook. Учебный контейнер доступен только на loopback и остановлен, существующие workflows не менялись. Клики редактора, production-публикация, Cloud, proxy, замена рабочего ключа, HMAC/JWT, TLS-конфигурация и полный аудит безопасности не тестировались. Обложка — редакционная AI-иллюстрация с маской вместо ключа, не снимок интерфейса.
Частые вопросы
Почему неправильный ключ даёт 403, а не 401?
В проверенном n8n 2.42.4 эта настройка Webhook вернула 403. Смотрите фактический ответ своего экземпляра и проверяйте, что рабочие узлы не запустились.
Можно передать ключ в ссылке?
Не для описанного Header Auth. Здесь проверяется X-Ezgpt-Key в заголовке. Query-параметр не прошёл тест и может оставить секрет в истории URL.
Почему импортированный workflow просит credentials?
Секрет и ID чужого credential намеренно не включены в публичный JSON. Создайте собственный Header Auth credential и выберите его в Webhook.
Достаточно спрятать URL или настроить CORS?
Нет. Они не заменяют проверку секрета для внешнего HTTP-клиента. В этой инструкции отказ без ключа обеспечивает Header Auth.
Ключ сохранён в credentials: значит, его нет в истории?
Нет такой гарантии. В нашем тесте значение присутствовало в данных успешного execution. Ограничивайте доступ к истории и не пересылайте сырые входные заголовки.