Аутентификация
Четыре схемы аутентификации ActionPulse — токен доступа, ключ приёма, токен релизов и ключ в адресе. Как получить токен, что делать с истёкшим и какой код придёт при неверном типе.
На этой странице
В 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 приходит даже если токена уже не было.
Что учесть при вызове из кода
- Права не выводятся из токена. Роль и членство перечитываются из базы на
каждом запросе, поэтому отзыв доступа действует немедленно, а разобранное
клиентом содержимое токена — не основание для решений о правах. Пользователь,
исключённый из организации, получит
401unauthorized, а не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=. Если такие есть — это устаревший ключ, который пора заменить. - Разбор конкретных кодов ответа по симптомам — в дереве диагностики.