Skip to Content
Справочник APIАутентификация

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

В InfraIO Pay есть два API-уровня с разными моделями аутентификации. Выбирайте тот, который соответствует вызывающей стороне:

УровеньПрефикс путиАудиторияАутентификация
Мерчантский B2B/b2b/v1/*Ваш серверПодпись запросов HMAC-SHA256
Панель управленияПо сервисам: /auth/*, /payment/*, /merchant/*, /event/*, /user/*, …Браузерные сессии для панели мерчантаBearer JWT

Эта страница описывает B2B-уровень — тот, который вы вызываете со своего сервера с парой API-ключей. Если вы встраиваете панель InfraIO или строите внутренние инструменты, используйте уровень панели управления (отдельная документация, пока не опубликована).

Gateway маршрутизирует каждый уровень по ведущему префиксу, который он срезает перед пересылкой: /b2b/v1/checkout-sessions/quick достигает payment-service как /v1/checkout-sessions/quick, а /payment/v1/orders панели достигает его как /v1/orders. Поэтому если вы видите голые пути /v1/* где-то ещё, это внутренний backend-путь после удаления публичного префикса — ваш клиент всегда отправляет форму с префиксом. (Одно следствие для подписания: каноническая строка B2B подписывает путь вместе с префиксом /b2b — см. ниже.)

Endpoint’ы

ОкружениеBase URL
Тестовоеhttps://api-dev.infraio.xyz
Боевоеhttps://api.infraio.xyz

Шаблон URL тот же — окружение определяется по префиксу ключа (pk_test_… или pk_live_…), а не по URL.

Пара ключей

Из панели мерчанта вы получаете два значения (Developers → API keys → + Add key):

  • Publishable-ключ (pk_test_… или pk_live_…) — идентифицирует ваш аккаунт. Передаётся как X-Client-ID. Безопасно встраивать в ваш браузерный бандл (SDK уже это делает).
  • Secret-ключ (sk_test_… или sk_live_…) — ключ HMAC-подписи. Только серверный. Относитесь к нему как к паролю базы данных.

Если secret-ключ когда-либо попал в браузерный бандл, git-репозиторий, лог-строку или общий чат — немедленно отзовите его из панели. Окна перекрытия нет; отзыв мгновенный. Выпустите новый ключ и переразверните.

Подписание запроса

Каждый вызов /b2b/v1/* несёт три заголовка:

X-Client-ID: pk_live_70d0becbd7a53047b0dfe88a960d10ad X-Timestamp: 1715990400 X-Signature: 9a8b7c6d… (hex HMAC-SHA256)

Подпись вычисляется по канонической строке:

METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY
  • METHOD — HTTP-глагол в верхнем регистре (POST, GET, …).
  • PATH — путь запроса включая префикс /b2b, без хоста и без query-строки (например, /b2b/v1/checkout-sessions/quick). Gateway проверяет подпись по сырому входящему пути до срезания /b2b, поэтому префикс должен присутствовать. Query-параметры не подписываются — для GET …?cursor=…&limit=20 подписывайте только путь, без части ?….
  • TIMESTAMP — unix-секунды как десятичная строка (например, "1715990400"), точно совпадающая с X-Timestamp.
  • BODY — сырые байты тела запроса. Пустая строка для GET/DELETE.

Подписывайте с помощью HMAC-SHA256 ключом secret, вывод hex:

import { createHmac } from "node:crypto"; function sign({ method, path, body, secret }: { method: string; path: string; body: string; secret: string; }) { const timestamp = Math.floor(Date.now() / 1000).toString(); const input = [method.toUpperCase(), path, timestamp, body].join("\n"); const signature = createHmac("sha256", secret).update(input).digest("hex"); return { timestamp, signature }; }

Почему HMAC, а не Bearer?

API на чистых Bearer-токенах отправляет ваш единственный секрет по сети при каждом запросе. Любой, кто получит лог одного прокси с TLS-терминацией, получает ключи от вашего аккаунта. Подпись HMAC означает, что секрет никогда не путешествует — только его производная подпись, одноразовая (привязанная к этому конкретному запросу и к этой конкретной минуте).

Компромисс: подпись нужно вычислять для каждого вызова. Серверный SDK скрыл бы это; пока мы его не выпустим, хелпер выше занимает ~15 строк на каждом языке.

Допуск по времени

Связывающий допуск составляет ±5 минут (300 секунд), его обеспечивает merchant-service при проверке подписи. Сам gateway чуть менее строг (310с) как защита в глубину, но запрос, прошедший gateway и не прошедший внутреннюю проверку, всё равно закончится ошибкой 401 invalid_signature — принимайте 300с за контракт. Из этого следуют две вещи:

  1. Синхронизируйте часы сервера через NTP. Долгоживущий cron со смещёнными часами будет давать сбои время от времени.
  2. Не предвычисляйте и не ставьте подписи в очередь. Если запрос просидит в очереди повторов более 5 минут, его подпись истечёт.

Scope’ы ключей

Secret-ключи несут один или несколько из этих наборов scope’ов:

ScopeНазначение
readЧтение списков и единичных заказов, сессий, возвратов
write_orderСоздание сессий checkout, заказов
write_refundВыпуск возвратов, генерация refund-request token’ов
webhook_manageСоздание/обновление/удаление webhook-endpoint’ов

По умолчанию панель выдаёт ключ с «полным доступом» (все четыре scope’а). Вы можете выпустить ключ с ограниченным scope’ом из Developers → API keys → + Add key, отметив только те scope’ы, которые нужны интеграции.

Применение scope’ов на данный момент рекомендательное, а не принудительное. Scope’ы записываются на ключе и показываются вам в панели, но middleware gateway пока не отклоняет вызовы вне scope’а — любой валидный ключ sk_… сегодня ведёт себя как ключ с полным доступом. Применение scope’ов на уровне endpoint’а запланировано на следующий релиз. Не полагайтесь на scope’ы как на границу безопасности пока что; считайте их метками и используйте ротацию / отзыв ключей, чтобы реально ограничивать доступ в данный момент.

Где проверяется подпись

Проверка HMAC происходит один раз, на gateway. Gateway:

  1. Читает X-Client-ID, X-Timestamp, X-Signature.
  2. Находит мерчанта и секрет по pk_…, проверяет временное окно, пересчитывает подпись, сравнивает за константное время.
  3. При успехе срезает auth-заголовки, проставляет внутренние заголовки (X-B2B-Auth: 1, X-Merchant-ID, X-Merchant-Domain) и пересылает запрос в downstream-сервис (payment-service, merchant-service и т. д.). Окружение и разрешённые scope’ы сегодня НЕ инжектируются — downstream-код, которому нужно окружение, выводит его из тела запроса / per-merchant конфигурации, а не из заголовков.
  4. При неудаче возвращает 401 INVALID_SIGNATURE, не трогая backend.

Downstream-сервисы не перепроверяют HMAC — они доверяют инжектированным заголовкам gateway и работают с тем мерчантом, которого определил gateway. Они не делают scope-gating по endpoint’у тоже: как отмечено выше, scope ключа не инжектируется, поэтому любой аутентифицированный sk_… достигает любого endpoint’а своего мерчанта (применение scope’ов сейчас рекомендательное — см. callout в разделе Scope’ы ключей.) Это важно в двух аспектах:

  • Если вы держите собственный reverse-прокси перед InfraIO Pay, не срезайте X-B2B-Auth / X-Merchant-ID (и не подделывайте их — gateway отклоняет входящие запросы, несущие их на публичной кромке).
  • Пути публичной сети (/b2b/v1/*) — единственный уровень, на котором выполняется HMAC-шаг. Внутренний gRPC между нашими сервисами использует mTLS — другую модель доверия, которая не принимает X-Client-ID.

Что дальше

  • Ошибки — форма ответа при 4xx/5xx.
  • Безопасность → API-ключи — ротация, отзыв, что делать, если секрет утёк.
  • Webhooks → Проверка подписи — использует другую схему HMAC (заголовок X-Signature: sha256=…, подписывает X-Timestamp + "." + raw_body плюс опциональный X-Signature-Prev в течение 24-часового grace-окна ротации). Не путайте схемы — алгоритм хэширования общий, но подписываемые байты и семейство секретов (whsec_… против sk_…) разные.