PDF
Розділ: Автентифікація

Автентифікація

API-токени asfa_ і підпис запитів обміну X-Signature v2: алгоритм, приклади на curl, Python і JavaScript, контрольний приклад.

В ApexSFA два способи автентифікації інтеграцій:

СпосібДе застосовуєтьсяЗаголовки
API-токен asfa_…Файли заказів виробника (/api/v1/exchange/*)Authorization: Bearer asfa_…
Ключ обміну + підписОбмін з обліковою системою (/api/v1/webhooks/1c/*)X-Tenant-Id, X-Signature: t=…,v2=…

Вихідні вебхуки ApexSFA підписує секретом підписки — перевірка описана в розділі 6.

Усі запити — лише через HTTPS. Секрети (токени, ключі обміну, ключі SFTP) не передавайте в URL, не пишіть у логи й не комітьте в репозиторій.


2.1. API-токени

Формат і зберігання

  • Токен має вигляд asfa_ + 40 випадкових символів, наприклад asfa_Qm9rZ3hYc2VjcmV0LWV4YW1wbGUtMTIzNDU2Nzg5 (вигаданий).
  • ApexSFA зберігає лише хеш токена. Відкритий токен показується один раз — під час видачі або перевипуску. Загубили — лише перевипуск.

Передача

HTTP
Authorization: Bearer asfa_Qm9rZ3hYc2VjcmV0LWV4YW1wbGUtMTIzNDU2Nzg5

Тенант визначається токеном — X-Tenant-Id не потрібен.

Права токена

Права токена задаються scope. Для файлів заказів потрібен scope exchange:orders — його ми вказуємо під час видачі. Токен для файлів заказів привʼязується до конкретного виробника: заявки з файлів цього токена отримують виробника з токена, навіть якщо реквізити постачальника у файлі неповні.

Видача, ротація, відкликання

Токени видає команда ApexSFA на запит дистрибʼютора. Один токен — один виробник.

  • Перевипуск — новий секрет; старий перестає діяти одразу. Щоб перейти без простою, попросіть другий токен, переключіть клієнт і після цього відкличте перший.
  • Відкликання — токен перестає діяти негайно.
  • Рекомендована ротація: раз на 6–12 місяців і негайно — при підозрі на витік.

Ліміт запитів

На кожен токен — 100 запитів у вікні 60 с (якщо для токена не погоджено інше). Вікно починається з першого запиту. Перевищення → 429; заголовка Retry-After немає — зачекайте до хвилини.

Помилки API-токена

HTTPmessageПричина
401Bearer API token requiredНемає заголовка Authorization: Bearer …
401Invalid API tokenТокен не знайдено (помилка в токені або його перевипущено)
401Token is revokedТокен відкликано
401Token has expiredМинув строк дії токена
403Token scope 'exchange:orders' requiredТокену бракує прав
429Rate limit exceeded: 100/minПеревищено ліміт токена

2.2. Підпис запитів обміну з обліковою системою

Ендпоінти обміну не використовують токени. Кожен запит підписується ключем обміну — секретом, який знають лише ApexSFA і ваша облікова система.

Заголовки

ЗаголовокОбовʼязковийОпис
X-Tenant-Idтак*UUID тенанта (точки синхронізації). *Можна не передавати, якщо в JSON-тілі є "tenant_id"
X-Signatureтакt=<unix-час>,v2=<hex>
Content-Typeтакapplication/json; charset=utf-8

Алгоритм v2

t        = поточний Unix-час у секундах (ціле, UTC)
body     = ТОЧНІ байти тіла запиту, як вони підуть у мережу (UTF-8)
message  = str(t) + "." + body + "." + secret
v2       = hex( SHA-256( message ) )          # 64 символи, нижній регістр
X-Signature: t=<t>,v2=<v2>

Схема однаково реалізується на будь-якій платформі, де є SHA-256.

Увага. Підписуйте рівно ті байти, що відправляєте. Не форматуйте JSON повторно після підпису, не додавайте BOM, не змінюйте переводи рядків — інакше 401.

  • Порожнє тіло сервер трактує як {} — для запитів без даних відправляйте тіло {} і підписуйте його.
  • Розбіжність t із часом сервера — не більше ±300 с. Синхронізуйте годинник (NTP), інакше всі запити отримуватимуть 401.
  • Той самий заголовок X-Signature (той самий t і те саме тіло) вдруге не приймається. Для повторної відправки того ж пакета підпишіть його заново з новим t. Якщо надсилаєте однакові тіла частіше ніж раз на секунду (наприклад, кілька outbox/pull поспіль), додайте в тіло унікальне поле "request_nonce": "<uuid>" — невідомі поля сервер ігнорує.

Приклади підпису

BODY='{"batch_size":50}'
TS=$(date +%s)
SIG=$(printf '%s' "$TS.$BODY.$SECRET" | sha256sum | cut -d' ' -f1)
curl -s -X POST "https://api.apexsfa.com/api/v1/webhooks/1c/outbox/pull" \
  -H "Content-Type: application/json; charset=utf-8" \
  -H "X-Tenant-Id: $TENANT_ID" \
  -H "X-Signature: t=$TS,v2=$SIG" \
  --data-binary "$BODY"

Псевдокод для будь-якої платформи

Функція ПідписЗапиту(ТілоРядкомUTF8, Секрет)
    Час = ПоточнийUnixЧасUTC()                        // ціле число секунд
    Рядок = Рядок(Час) + "." + ТілоРядкомUTF8 + "." + Секрет
    Хеш = SHA256(БайтиUTF8(Рядок))                    // без BOM
    Повернути "t=" + Рядок(Час) + ",v2=" + НижнійРегістр(HEX(Хеш))
КінецьФункції

Контрольний приклад

Значення вигадані — лише для перевірки вашої реалізації:

secret = test-secret-0123456789
t      = 1761552000
body   = {"batch_size":50}
рядок  = 1761552000.{"batch_size":50}.test-secret-0123456789
v2     = 643a26cf3cd6ad12c10bc6c27e729aa4449e5630a515e7459e01b20c4c08ea4c
X-Signature: t=1761552000,v2=643a26cf3cd6ad12c10bc6c27e729aa4449e5630a515e7459e01b20c4c08ea4c

Перевірка в терміналі: printf '%s' '1761552000.{"batch_size":50}.test-secret-0123456789' | sha256sum має дати той самий hex.

Ключ обміну й ротація

  • Кожна точка синхронізації (філія з окремою базою обліку) має свій тенант і свій ключ обміну. Запит із ключем точки працює лише з даними цієї точки.
  • Ключ видає команда ApexSFA під час підключення точки. Передайте його в налаштування обміну облікової системи; у коді, логах і листуванні ключ не зберігайте.
  • При заміні ключа попередній діє ще 24 години — за цей час оновіть ключ у налаштуваннях обміну.
  • Обмін тимчасово недоступний (401), якщо його вимкнено для тенанта або тенант призупинено.

Помилки автентифікації обміну

HTTPПричина
401 INVALID_CREDENTIALSНемає або невірний X-Tenant-Id; обмін не підключено або вимкнено; тенант призупинено; невірний підпис; час поза ±300 с; повтор підпису
429 RATE_LIMIT_EXCEEDEDПонад 600 запитів за 60 с з одного IP на тенант