Урок курса

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.manualTrigger typeVersion 1 — Узел Manual Trigger в выданном export

  • n8n-nodes-base.set typeVersion 3.4 — Узел Scenario Config в выданном export

  • n8n-nodes-base.switch typeVersion 3.4 — Узел Source Mode Switch в выданном export

  • n8n-nodes-base.httpRequest typeVersion 4.3 — Узел Cursor Request в выданном export

  • n8n-nodes-base.code typeVersion 2 — Узел Validate Body в выданном export

  • n8n-nodes-base.stopAndError typeVersion 1 — Узел Auth Failure в выданном export

  • n8n-nodes-base.wait typeVersion 1.1 — Узел Wait Before Retry в выданном export

  • n8n-nodes-base.convertToFile typeVersion 1.1 — Узел Convert Result to JSON File в выданном export

  • n8n-nodes-base.readWriteFile typeVersion 1 — Узел Write result.json в выданном export

Подготовка

  1. Создать рабочую копию. Выполните python assets/setup.py, затем импортируйте submission/workflow.json в n8n 2.39.9.
    Ожидаемое наблюдение: Создан отдельный submission/workflow.json; исходный starter остаётся неизменным.

Запуск

  1. Исправить workflow. Внесите требуемое lesson-specific изменение в импортированный граф и экспортируйте его поверх submission/workflow.json.
    Ожидаемое наблюдение: Изменение присутствует в параметрах и connections экспортированного workflow.

  2. Проверить 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.

Сброс

  1. Сбросить 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 не принимаются как доказательство.

Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку