Авторизация внешних интеграций¶
Назначение¶
Этот документ описывает, как работает machine-to-machine авторизация для внешних интеграций.
Один integration client может работать с одной или несколькими организациями, если такой доступ разрешен на стороне сервера.
Термины¶
integration client: серверная запись сclientIdиclientSecretдоступ к организации: allowlist-запись, которая разрешает конкретному integration client работать с конкретной организациейtechnical user: внутренний технический пользователь, которого система создает для конкретной парыорганизация + integration clientX-Organization-Id: HTTP-заголовок, через который выбирается контекст организации для org-scoped запросов
Общая схема работы¶
- Внешней системе выдаются
clientIdиclientSecret. - Внешняя система получает access token через
POST /api/account/token. - Внешняя система вызывает API с заголовком
Authorization: Bearer <access_token>. - Для методов, работающих в контексте организации, дополнительно передается
X-Organization-Id. - Сервер проверяет, что integration client имеет доступ к указанной организации. Для всех новых организаций доступ автоматически есть.
- Если доступ разрешен, сервер автоматически переключает выполнение на technical user этой организации.
Внешняя система не передает userId и не выбирает внутреннего пользователя вручную.
Получение токена¶
Запрос¶
POST /api/account/token
Content-Type: application/json
{
"grantType": "client_credentials",
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
Важно¶
Текущая реализация ожидает JSON body.
Ответ¶
{
"accessToken": {
"token": "<jwt>",
"expiresIn": 3600
},
"refreshToken": null,
"currentUser": null,
"requiresTwoFactor": false,
"twoFactorProvider": null,
"twoFactorToken": null
}
Важно¶
refreshTokenдля machine-to-machine авторизации не используется- новый access token нужно получать повторным запросом с теми же
clientIdиclientSecret
Семантика токена¶
Выданный JWT идентифицирует integration client, а не бизнес-пользователя.
Это означает:
- сам токен не привязан к одной организации
- один и тот же токен можно использовать для разных организаций, если у integration client есть доступ к ним
- контекст организации выбирается на каждый запрос отдельно через
X-Organization-Id
Внешней системе нужно воспринимать access token как непрозрачный токен. Не нужно строить бизнес-логику на внутренних JWT claims.
X-Organization-Id¶
Когда заголовок обязателен¶
X-Organization-Id обязателен для любого запроса, который должен выполняться в контексте конкретной организации.
Пример:
Что делает сервер¶
Если в запросе передан X-Organization-Id, сервер:
- читает
clientIdиз machine token - проверяет, что integration client имеет доступ к указанной организации
- заменяет текущий principal на этого technical user
- передает дальше в систему уже обычные внутренние
userIdиorganizationId
За счет этого обычная бизнес-логика, валидаторы работают так, как будто запрос выполнил внутренний пользователь организации.
Что будет, если заголовок не передать¶
Для org-scoped integration endpoints запрос будет отклонен с 401 Unauthorized.
Типовые причины:
- не передан
X-Organization-Id - передан некорректный
X-Organization-Id
Модель доступа¶
Доступ контролируется двумя серверными сущностями:
IntegrationClient: хранитclientIdиclientSecretOrganizationIntegrationClient: allowlist-запись, которая связывает integration client с конкретной организацией
Если для пары clientId + organizationId нет allowlist-записи, org-scoped запросы будут отклоняться.
Метод создания организации¶
Endpoint¶
POST /api/integrations/organizations/apply
Авторизация¶
- обязателен
Authorization: Bearer <access_token> X-Organization-Idдля этого метода не нужен
Request body¶
Все поля опциональны, кроме тех случаев, когда они обязательны по бизнес-правилам на стороне клиента. Сервер выполняет валидацию формата inn и kpp, если они переданы.
Поведение¶
Если передан inn:
- сервер ищет существующую организацию по
inn - если организация уже есть, возвращается ее существующий идентификатор
- если организации нет, создается новая организация и возвращается ее идентификатор
Если inn не передан:
- сервер использует специальную организацию-отстойник
- если организация-отстойник еще не существует, она создается автоматически
- возвращается идентификатор этой организации
В обоих случаях сервер также гарантирует, что:
- integration client связан с организацией
- для пары
organization + integration clientсуществует technical user - для этого technical user существует
SyncSystemсBehavior = Read
Ответ¶
Вызов других org-scoped API¶
Тот же machine token можно использовать и для других API-методов, которые зависят от текущего внутреннего пользователя и организации, если:
- integration client имеет доступ к целевой организации
- передан
X-Organization-Id - целевой метод доступен ролям technical user
Для таких запросов внешняя система должна вызывать нужный API обычным способом и не должна самостоятельно передавать внутренний userId, если только этого явно не требует контракт конкретного метода.
Чеклист интеграции¶
- Получить
clientIdиclientSecretиз CARGO.RUN от разработчиков. - Запросить access token через
POST /api/account/token. - Безопасно хранить access token и запрашивать новый токен повторно до или после истечения срока действия.
- Для создания организации вызывать
POST /api/integrations/organizations/applyбезX-Organization-Id. - Сохранить возвращенный
organizationId. - Для любого org-scoped метода передавать
X-Organization-Idс этим идентификатором. - Использовать один и тот же access token для нескольких организаций только в том случае, если на сервере для этого выдан allowlist-доступ.
Примечания¶
- внешней системе не нужно ожидать, что в JWT claims будет бизнесовый
userId - контекст организации выбирается заголовком, а не самим токеном