К содержанию
ActionPulse

Аутентификация

Четыре схемы аутентификации ActionPulse — токен доступа, ключ приёма, токен релизов и ключ в адресе. Как получить токен, что делать с истёкшим и какой код придёт при неверном типе.

Кому
Разработчикам, вызывающим API из кода
Проверено
На этой странице

В API ActionPulse четыре схемы аутентификации, и они не заменяют друг друга: у каждой свой способ передачи, своё место выпуска и своя граница доверия. Эта страница нужна, когда надо получить первый токен из кода, разобраться, почему запрос отвечает 401, или решить, каким ключом ходить из CI/CD.

Какая схема применяется к конкретной операции, указано у неё в справочнике API — это машинный перечень, и он точнее любого пересказа. Здесь — то, чего в спецификации нет: как токен получить, как его продлить и что именно ломается при подмене одного типа другим.

Четыре схемы

Схема Как передаётся Что ею можно Где взять
Токен доступа Authorization: Bearer <токен> основной API — всё, что разрешает роль пользователя вход в /api/v1/auth/login
Ключ приёма Authorization: Bearer <ключ> приём событий — пять операций записи кабинет или /api/v1/projects/YOUR_PROJECT_ID/keys
Токен релизов Authorization: Bearer pp_rel_… ровно одна операция: отметка деплоя /api/v1/projects/YOUR_PROJECT_ID/release-tokens
Ключ приёма в адресе ?key=<ключ> те же пять операций приёма, только для устаревших ключей ничего нового не выпускается

По умолчанию каждая операция основного API требует токен доступа. Исключения объявлены явно у самой операции: либо она вообще не требует аутентификации, либо принимает ключ приёма, либо — в единственном случае — токен релизов. Ключом приёма работают ровно пять операций записи на поверхности приёма, токеном релизов — одна. У каждого раздела справочника указано, сколько его операций доступны без токена доступа.

Токен доступа

Как получить

Вход — POST /api/v1/auth/login с телом {"email":…, "password":…}. Дополнительно можно передать org_id, если у пользователя несколько организаций, и mfa_code, если у него включена двухфакторная защита.

Ответ 200 содержит access_token в теле. Долгоживущий токен обновления в теле не приходит никогда: он ставится в httpOnly-cookie pp_rt, ограниченную путём /api/v1/auth, — браузер не отдаёт её ни коду страницы, ни остальным путям API.

curl

# Cookie-файл нужен, чтобы потом обновлять токен доступа.
curl -sS -X POST https://YOUR_ACTIONPULSE_HOST/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -c pp-cookies.txt \
  -d "{\"email\":\"$PP_EMAIL\",\"password\":\"$PP_PASSWORD\"}"

Браузер

// Токен доступа живёт только в памяти модуля: ни localStorage, ни cookie.
let accessToken = null;

async function login(email, password, mfaCode) {
  const response = await fetch('https://YOUR_ACTIONPULSE_HOST/api/v1/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'include', // иначе cookie обновления не установится
    body: JSON.stringify({ email, password, mfa_code: mfaCode }),
  });

  if (!response.ok) {
    const { error } = await response.json();
    throw new Error(`login failed: ${response.status} ${error.code}`);
  }

  const data = await response.json();
  if (data.mfa_required) return { mfaRequired: true };

  accessToken = data.access_token;
  return { mfaRequired: false };
}

Если у пользователя включён TOTP, вход возвращает не токен, а объект {"mfa_required": true}. Повторите тот же запрос, добавив mfa_code — текущий шестизначный код приложения-аутентификатора или один неиспользованный код восстановления.

Что делать с истёкшим

Токен доступа живёт 15 минут — это жёсткая граница проверяющей стороны, а не настройка. Истёкший токен отвечает 401 unauthorized на любой операции. Правильная реакция — один вызов обновления и один повтор исходного запроса:

curl -sS -X POST https://YOUR_ACTIONPULSE_HOST/api/v1/auth/refresh \
  -b pp-cookies.txt -c pp-cookies.txt

Обновление читает токен только из cookie pp_rt — тела запроса не нужно. В ответ приходит новый access_token, а сама cookie заменяется на новую. Необязательное поле org_id в теле переключает организацию: сервер выводит пользователя из токена обновления и заново проверяет активное членство, прежде чем выдать новый контекст.

Практичная схема для клиента: держать токен доступа в памяти, при 401 один раз вызвать обновление и повторить запрос, а при 401 от самого обновления — отправить пользователя на вход. Бесконечный цикл «обновить и повторить» ничего не спасёт и быстро упрётся в ограничение частоты.

Завершение сессии — POST /api/v1/auth/logout без тела: cookie гасится, ответ 204 приходит даже если токена уже не было.

Что учесть при вызове из кода

  • Права не выводятся из токена. Роль и членство перечитываются из базы на каждом запросе, поэтому отзыв доступа действует немедленно, а разобранное клиентом содержимое токена — не основание для решений о правах. Пользователь, исключённый из организации, получит 401 unauthorized, а не 403.
  • Заголовок Origin проверяется. У операций, аутентифицируемых cookie (обновление и выход), присутствующий Origin должен входить в разрешённый список, иначе 403. Серверный клиент этот заголовок обычно не отправляет и ограничения не замечает; браузерный обязан ходить с credentials: 'include' и с разрешённого домена.
  • Ограничение частоты у входа жёстче, чем у остальных операций. У всей группы входа и регистрации — 10 попыток с одного адреса в минуту, плюс 5 попыток в минуту на один адрес электронной почты. У обновления и выхода отдельный бюджет: 120 запросов с одного адреса в минуту — иначе перезагрузка страницы, которая всегда обменивает cookie на новый токен доступа, съедала бы лимит входа. Превышение — 429 с заголовком Retry-After в секундах; полная картина — в статье об ограничениях частоты.
  • Сервисных токенов для основного API нет. Любой вызов идёт от имени пользователя с его ролью; единственное исключение — токен релизов ниже. Для автоматизации заведите отдельного пользователя с минимально достаточной ролью и не используйте токен владельца организации.

Ключ приёма

Ключ приёма аутентифицирует пять операций записи на поверхности приёма: отправку событий, identify, alias, записи сессий и захват элемента. Передаётся так же, как токен доступа, — Authorization: Bearer <ключ>.

Типов ключа три, и тип зашит в префикс значения: публичный браузерный токен pp_bt_…, секретный серверный ключ pp_sk_… и устаревший pp_wk_…. Права определяет именно тип плюс явная область действия — заявить в запросе, что вы «на самом деле сервер», нельзя. Полное сравнение типов, их области действия и порядок перехода с устаревшего префикса — на странице типов ключей.

Выпуск, ротация и отзыв доступны роли администратора и владельцу; полное значение показывается один раз, в базе остаётся только его хеш и безопасный восьмисимвольный префикс.

Ещё один способ передачи существует для браузера: поле credential в теле JSON, и только для браузерного токена и только на двух операциях — /v1/track и /v1/replay. Он нужен для отправки на выходе со страницы, когда браузерный beacon не умеет ставить заголовки. Серверному ключу этот способ закрыт.

Чем ключ приёма отличается от токена доступа

Оба передаются одним и тем же заголовком, и на этом сходство заканчивается.

Токен доступа Ключ приёма
Привязан к пользователю и организации одному проекту
Срок жизни 15 минут у серверного может отсутствовать, у браузерного обязателен
Как получить вход с паролем выпуск администратором, значение показывается один раз
Что даёт всё, что разрешает роль пользователя пять операций записи в рамках своих областей действия
Продление обновление по cookie не продлевается: ротация выдаёт новое значение
Где может лежать только в памяти вызывающего кода серверный — в окружении бэкенда, браузерный — публично на странице

Главное различие не в сроке, а в направлении: ключ приёма не даёт прочитать ни одного события, отчёта или настройки проекта — его операции только пишут. Публичную конфигурацию сбора трекер запрашивает по безопасному восьмисимвольному префиксу, а не по самому ключу, и в ответе приходят только включённые виды сбора. Обратное тоже верно: токеном доступа события не отправить — приём его не понимает.

Токен релизов

Отдельный узкий ключ для CI/CD: префикс pp_rel_, единственная фиксированная область действия release_markers:write и ровно одна доступная операция — POST /api/v1/projects/YOUR_PROJECT_ID/release-markers/deploy. Приём его не принимает, остальные операции основного API — тоже.

Выпускается в POST /api/v1/projects/YOUR_PROJECT_ID/release-tokens роли администратора и выше, показывается один раз. Отзыв доступен всегда.

Отметка деплоя требует заголовок Idempotency-Key — от 8 до 128 печатных символов без пробелов и запятых. Контракт повтора точный:

Ответ Что произошло
201 создана новая отметка
200 с заголовком Idempotency-Replayed: true тот же ключ и то же тело — повтор уже выполненного запроса
409 тот же ключ с другим телом

Поэтому безопасный ключ идемпотентности — что-то стабильное для конкретного деплоя: идентификатор сборки или коммита, а не случайное значение на каждую попытку. Подробнее о повторах — в статье об идемпотентности.

Что доступно без аутентификации

Часть операций не требует вообще никакого ключа. Пять категорий, и других нет:

  • Служебная проверка живости — одна операция, отвечает у обеих поверхностей.
  • Публичные ресурсы приёма — файлы трекера, публичная конфигурация сбора и кросс-доменные предзапросы браузера ко всем операциям записи.
  • Вход и регистрация — регистрация и её подтверждение, вход, обновление и завершение сессии, приглашения, сброс пароля, вход через внешнего провайдера. Аутентифицироваться нечем, потому что это и есть операции получения доступа.
  • Внешние обратные вызовы — вебхук платёжного провайдера в облаке и отписка от маркетинговых писем по токену из письма.
  • Разбор публичной ссылки-шеринга — анонимная граница, привязанная к токену самой ссылки.

Неправильный тип ключа

Что отправили Куда Ответ Код
Ничего основной API 401 unauthorized
Ключ приёма основной API 401 unauthorized
Токен доступа приём 401 unauthorized
Токен релизов любая операция, кроме отметки деплоя 401 unauthorized
Истёкший или отозванный ключ либо токен любая поверхность 401 unauthorized
pp_bt_… или pp_sk_… в ?key= приём 401 unauthorized
Не браузерный токен в поле credential приём 401 unauthorized
Ключ приёма верного формата, но не того типа или области приём 403 credential_scope_forbidden
Браузерный токен с домена вне своего списка приём 403 credential_origin_forbidden
Ключ, выпущенный до разделения прав на связывание identify, alias 403 credential_rotation_required
Токен доступа без нужной роли основной API 403 forbidden
Токен доступа на чужой проект или организацию основной API 404 not_found

Читать таблицу удобно так: 401 — «я не понял или не признал ваш ключ», 403 — «ключ признан, но этого ему нельзя», 404 — «объекта для вас не существует». Последнее сделано намеренно: чужой проект не должен подтверждать свой факт существования отказом в доступе.

Сообщение в 401 не говорит, что именно не так: отозванный, истёкший и просто неверный ключ выглядят одинаково, чтобы ответ не помогал подбирать значения. Различается только «ключа нет вообще» и «ключ не признан». Ни один из ответов не возвращает присланное значение ключа или домен. Все ошибки приходят в одном конверте:

{ "error": { "code": "unauthorized", "message": "…", "details": {} } }

Полный перечень машинных кодов и правила повторов — в статье об ошибках.

Чего делать нельзя

Передавать ключ в адресе запроса. Такая возможность существует, но только как совместимость: параметр ?key= принимается исключительно для устаревших ключей pp_wk_… и только на пяти операциях приёма. Браузерный токен и серверный ключ в адресе отклоняются всегда. Успешный запрос через адрес помечается в ответе заголовком Deprecation: true — без самого значения ключа и без даты отключения.

Когда это уместно: у вас уже есть работающий устаревший ключ и есть путь, где заголовок физически недоступен, — отправка на выходе со страницы. Во всех остальных случаях это лишний риск, потому что адрес запроса попадает в логи прокси, CDN, систем трассировки и мониторинга, в историю браузера и в заголовок Referer, а ключ из логов не отзывается сам. Новые браузерные потоки вместо адреса используют поле credential в теле, а правильное решение для устаревшего ключа — перейти на новые префиксы и отозвать старый.

Класть серверный ключ в браузер. pp_sk_… даёт право отправлять подтверждённые бизнес-факты; в разметке, бандле, контейнере тег-менеджера и клиентских логах его быть не может. Для браузера есть публичный токен с обязательной привязкой к домену и сроком действия.

Хранить токены в браузерном хранилище. Токен доступа держите в памяти приложения, токен обновления вообще не попадает в код страницы — он живёт в cookie, недоступной JavaScript. Перенос любого из них в localStorage превращает любую XSS-уязвимость на сайте в кражу сессии.

Пробовать ключ приёма как токен доступа и наоборот. Это не «почти работает», а гарантированный 401: поверхности разбирают значения разных форматов. Разница поверхностей — на странице двух поверхностей.

Что проверить

  • В коде нет ни одного места, где токен доступа или ключ приёма записан строкой: оба читаются из окружения или из защищённого хранилища секретов.
  • Клиент обновляет токен доступа при 401 один раз и не крутит цикл; вызов обновления не выполняется параллельно с одним и тем же cookie.
  • Ограничение частоты у входа учтено: при 429 клиент ждёт столько, сколько сказано в Retry-After, а не повторяет сразу.
  • Автоматизация ходит от отдельного пользователя с минимально достаточной ролью, а отметки релизов — токеном релизов, а не токеном человека.
  • В логах прокси и в системе трассировки нет запросов с параметром key=. Если такие есть — это устаревший ключ, который пора заменить.
  • Разбор конкретных кодов ответа по симптомам — в дереве диагностики.