Урок курса
OAuth2, заголовки и диагностика 401/403
Продвинутый n8n: production-автоматизации и AI-агентыВ предыдущих уроках мы работали с Code-нодой и управляли структурой данных внутри workflow. Теперь workflow должен обращаться к внешнему API — а значит, нужно разобраться, как безопасно передать учётные данные, не записав секрет прямо в ноду.
Credential в HTTP Request: зачем и как прикрепить
Когда HTTP Request обращается к защищённому API, ему нужно передать что-то, что докажет идентичность: токен, ключ, пару client_id/client_secret. Есть три места, куда этот секрет технически можно вставить: прямо в URL (?api_key=abc123), в поле Headers ноды (Authorization: Bearer abc123) или через credential. Первые два варианта работают — но создают конкретные проблемы.
Секрет в URL попадает в логи сервера, историю браузера, заголовок Referer и, главное, в JSON-экспорт workflow. Достаточно поделиться workflow-файлом с коллегой — и ключ утёк. Секрет в поле Headers ноды чуть лучше, но в n8n это поле хранится в workflow JSON в открытом виде; оно видно в execution data и в любом бэкапе.
Credential решает эту проблему архитектурно: секрет хранится отдельно от workflow в зашифрованном хранилище n8n, зашифрован ключом из переменной окружения N8N_ENCRYPTION_KEY. В workflow JSON и в execution data попадает только имя credential — не значение. Когда HTTP Request выполняется, n8n читает credential из хранилища прямо перед отправкой запроса и подставляет нужные заголовки или токен в памяти, не записывая их в лог.
Для тестового API нужно выбрать тип credential, который соответствует механизму аутентификации. В n8n есть несколько встроенных типов:
- Header Auth — для API, которые ожидают фиксированный заголовок (например,
X-API-KeyилиAuthorization: Bearer <static_token>). - OAuth2 (Generic) — для API, которые требуют token exchange по протоколу OAuth2; n8n выполняет этот обмен сам.
- Basic Auth — для пары логин/пароль.
- Bearer Auth — для готового статического Bearer-токена.
- Query Auth — если API действительно требует ключ в query string.
Тип выбирается по документации или manifest конкретного API. Если API требует Bearer-токен, который не истекает, достаточно Header Auth. Если API возвращает client_credentials grant или authorization code — нужен OAuth2 Generic. Для generic credential путь в HTTP Request двухступенчатый: Authentication → Generic Credential Type, затем Generic Auth Type и нужный тип — например, Header Auth, Bearer Auth, Query Auth или OAuth2 API. После выбора появляется отдельное поле Credential for Header Auth (или для выбранного типа), где указывается сохранённый credential.
В JSON workflow остаётся ссылка на credential, а не его секретное значение.
Настройка OAuth2 и Header Auth credential для тестового API
Каждый из двух типов credential настраивается по-своему, потому что механизм аутентификации принципиально разный.
Header Auth credential — самый прямой случай. В форме создания credential указываются два поля: Name (имя заголовка, который нужно отправить, например X-API-Key) и Value (его значение). После сохранения credential в HTTP Request выберите Authentication → Generic Credential Type, затем Generic Auth Type = Header Auth и в поле Credential for Header Auth укажите нужный credential. При каждом запросе n8n добавит этот заголовок автоматически.
Важно: имя заголовка — это не произвольная метка credential, это буквально строка, которая уйдёт в HTTP-запрос; если API ожидает Authorization, а вы написали authorization — часть серверов воспримет это нормально (HTTP/1.1 заголовки case-insensitive), но некоторые прокси и gateway нет, поэтому лучше сверяться с manifest.
Generic Credential Type → OAuth2 API — сложнее, потому что за ним стоит token exchange. Набор обязательных полей зависит от Grant Type, который указан в manifest тестового API.
Client Credentials grant — серверный поток без участия пользователя. Форма требует:
- Access Token URL — endpoint, на который n8n отправляет POST для получения токена.
- Client ID и Client Secret.
- Scope — опционально; если manifest указывает scope, добавьте его здесь.
- Authentication — способ передачи секрета (обычно
BodyилиHeader; берётся из manifest).
Authorization URL для этого grant не нужен и в форме не присутствует. После сохранения credential n8n самостоятельно получает access_token и подставляет его в каждый запрос. Client Credentials обычно не выдаёт refresh_token; когда токен истекает, n8n запрашивает новый автоматически.
Authorization Code grant — поток с участием пользователя. Здесь форма включает дополнительные поля:
- Authorization URL — куда n8n перенаправляет для получения кода авторизации.
- Access Token URL — для обмена кода на токен.
- Client ID, Client Secret, Scope, Auth URI Query Parameters — по manifest.
После редиректа и подтверждения n8n завершает обмен и сохраняет токен. Если провайдер выдаёт refresh_token, n8n обновит access_token автоматически при истечении срока; если нет — потребуется повторная авторизация.
В обоих случаях при успешной настройке страница credential показывает статус Connected — это сигнал, что token exchange состоялся и токен получен. В HTTP Request выберите Authentication → Generic Credential Type, затем Generic Auth Type = OAuth2 API и нужный Credential for OAuth2 API: нода сама подставит актуальный Authorization: Bearer <token> перед вызовом.
Ключевой момент: вы не трогаете токен руками. Попытка скопировать его вручную из response и вставить как Header Auth value — это шаг назад: токен будет протухать, а workflow сломается молча.
Оба credential после создания видны только по имени в списке HTTP Request. Их значения нельзя прочитать из интерфейса повторно — только пересоздать.
Диагностика 401/403 и подтверждение успешного доступа по execution data
401 и 403 выглядят похоже — оба блокируют запрос — но причины у них разные, и лечатся они по-разному.
401 Unauthorized означает, что сервер не смог идентифицировать запрашивающего. Токен отсутствует, истёк, отозван или передан некорректно. Диагностика здесь ведётся не через просмотр значения токена в execution data — credential-заголовки туда не попадают, — а через проверку конфигурации credential: прикреплён ли он к ноде, совпадают ли Client ID, Access Token URL и grant type с manifest. Если credential подключён правильно, но 401 сохраняется — пересоздайте credential с параметрами строго по manifest и повторите execution.
403 Forbidden в контексте нашего тестового fixture означает: сервер идентифицировал запрос успешно, токен валиден, но выданные разрешения не покрывают запрошенный ресурс или действие. Причина здесь — неполный scope при создании OAuth2 credential: сервер выдал токен с ограниченными правами. Исправление: открыть credential, дописать нужный scope из manifest (например, добавить write к уже имеющемуся read), пересохранить и переавторизовать — n8n запросит новый токен с расширенным набором разрешений. Для Header Auth 403 в fixture означает, что ключ выдан для другой роли или endpoint — нужен другой ключ из manifest.
Важная оговорка: это поведение специфично для нашего fixture. В реальных API 403 может иметь иные причины — policy на уровне ресурса, ограничение по IP или роли на gateway, намеренное сокрытие ресурса. Начальные гипотезы в таком случае: scope, роль клиента, resource-level policy. Источником информации служат документация API и тело ошибки в response body.
После исправления запускаем execution и проверяем результат в execution data HTTP Request:
- Status Code должен быть 2xx (200, 201, 204 — зависит от endpoint).
- Body должен содержать expected response marker из fixture manifest — конкретное поле или строку, которая подтверждает ответ именно от нужного endpoint.
- Поле Credential в метаданных ноды фиксирует имя использованного credential.
Эти три факта и есть execution evidence: статус, marker, имя credential. Само значение access_token, client_secret или заголовка из Header Auth credential копировать не нужно — они не должны попадать в заметки, комментарии к workflow или текстовые поля рядом с нодой. Если токен скопирован «для проверки» — он стал частью workflow JSON и подлежит ротации.
Задача 1
HTTP Request получил 401, потому что не использует выданный credential. Как исправить причину, не выполняя token exchange вручную?
Задача 2
Как называется generic credential для хранения имени и значения пользовательского HTTP-заголовка?
Задача 3
Лаборатория: OAuth2, заголовки и диагностика 401/403
Разберите три похожих снаружи ответа API: успешный запрос, 401 из-за непривязанного credential и 403 из-за прав. Привяжите Header Auth через интерфейс n8n и не переносите секрет в workflow JSON.
Файлы лабораторной
Скачайте из блока «Файлы шага» n8n_lab_06_setup.py и n8n_lab_06_README.md. Запустите setup-скрипт в пустой папке: он восстановит рабочую структуру и создаст submission/workflow.json.
Зафиксированная среда
n8n
2.39.9; цель:either. Источник фиксации: Pinned course runtime 2.39.9; exact node typeVersions read from the supplied export on 2026-09-22.n8n-nodes-base.manualTriggertypeVersion1— Узел Manual Trigger в выданном exportn8n-nodes-base.settypeVersion3.4— Узел Scenario Config в выданном exportn8n-nodes-base.switchtypeVersion3.4— Узел Source Mode Switch в выданном exportn8n-nodes-base.httpRequesttypeVersion4.3— Узел Cursor Request в выданном exportn8n-nodes-base.codetypeVersion2— Узел Validate Body в выданном exportn8n-nodes-base.stopAndErrortypeVersion1— Узел Auth Failure в выданном exportn8n-nodes-base.waittypeVersion1.1— Узел Wait Before Retry в выданном exportn8n-nodes-base.convertToFiletypeVersion1.1— Узел Convert Result to JSON File в выданном exportn8n-nodes-base.readWriteFiletypeVersion1— Узел Write result.json в выданном export
Подготовка
- Создать рабочую копию. Выполните python assets/setup.py, затем импортируйте submission/workflow.json в n8n 2.39.9.
Ожидаемое наблюдение: Создан отдельный submission/workflow.json; исходный starter остаётся неизменным.
Запуск
Исправить workflow. Внесите требуемое lesson-specific изменение в импортированный граф и экспортируйте его поверх submission/workflow.json.
Ожидаемое наблюдение: Изменение присутствует в параметрах и connections экспортированного workflow.Проверить submission. Выполните python assets/run.py. Runner сам читает submission/workflow.json, прогоняет fixtures и перезаписывает observations/report; student_evidence не используется.
Ожидаемое наблюдение: Receipt N8N_LAB_06_OK появляется только для исправленного графа.
Матрица приёмки
credential bound. Runner подаёт fixture в deterministic engine после проверки текущего submission/workflow.json; ручные actual и execution_id не принимаются. Наблюдения: С привязанным credential fixture отвечает 200.; В export и execution output нет значения секрета.. Зафиксируйте: lesson_id, submission_sha256, case_id, derived_actual, observation_sha256, receipt.
missing credential. Runner подаёт fixture в deterministic engine после проверки текущего submission/workflow.json; ручные actual и execution_id не принимаются. Наблюдения: Без credential запрос останавливается с 401.; Причина отделена от ошибки прав.. Зафиксируйте: lesson_id, submission_sha256, case_id, derived_actual, observation_sha256, receipt.
wrong permission. Runner подаёт fixture в deterministic engine после проверки текущего submission/workflow.json; ручные actual и execution_id не принимаются. Наблюдения: Валидная аутентификация с недостаточными правами даёт 403.; Повторная авторизация не маскирует запрет.. Зафиксируйте: lesson_id, submission_sha256, case_id, derived_actual, observation_sha256, receipt.
Сброс
- Сбросить derived evidence. Выполните python assets/reset.py. Чтобы вернуть starter, отдельно снова выполните python assets/setup.py.
Ожидаемое наблюдение: Удалены observations.json и verification_report.json; workflow не подменяется скрытым эталоном.
Что отправить
Сдайте receipt из assets/run.py и сохраните generated evidence/verification_report.json. Runner не читает student_evidence.
Обязательные поля: lesson_id, submission_sha256, case_id, derived_actual, observation_sha256, receipt.
В поле ответа вставьте значение receipt из отчёта runner.
Границы проверки
Runner исполняет детерминированную учебную модель узлов и state/stub-контрактов после разбора export; живой n8n 2.39.9 остаётся отдельной ручной проверкой.
Ни actual, ни execution_id, ни текстовое заявление learner_change не принимаются как доказательство.
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
