Аутентификац ия
Все IDCloud API (контракты Web & SDK и API) используют OAuth2 с JWT Bearer Grant Type (RFC 7523). Вы генерируете кратковременный JWT assertion на своём бэкенде, обмениваете его на Bearer-токен и используете этот токен в каждом последующем запросе.
JWT assertion должен генерироваться исключительно на вашем бэкенде. Никогда не раскрывайте закрытый ключ во фронтенд-коде, мобильных приложениях, репозиториях или журналах.
Получение учётных данных
Прежде чем генерировать токены, вам нужен сервисный аккаунт, выданный Unico. Обратитесь в поддержку Unico и предоставьте:
- Название сервисного аккаунта (не более 12 символов)
- Имя, email и телефон ответ ственного лица (только номера Бразилии, США или Мексики)
Вы получите:
- Уникальное название аккаунта
- Tenant ID
- Базовую полезную нагрузку JWT
- Файл закрытого ключа (формат
.pem)
Используйте отдельные сервисные аккаунты для UAT и Production.
Создание JWT assertion
Assertion — это JWT в компактном формате JWS: {Base64url(Header)}.{Base64url(Payload)}.{Base64url(Signature)}.
{
"alg": "RS256",
"typ": "JWT"
}
| Claim | Значение | Примечания |
|---|---|---|
iss | <account_name>@<tenant_id>.iam.acesso.io | Предоставляется вместе с учётными данными |
aud | https://identityhomolog.acesso.io (UAT) или https://identity.acesso.io (Production) | Должен совпадать с хостом конечной точки токена |
scope | * | Предоставляет все разрешения |
iat | Временная метка Unix (в секундах) | Время выдачи JWT |
exp | iat + не более 3600 | Не может превышать 1 час от iat |
{
"aud": "https://identity.acesso.io",
"scope": "*",
"iat": 1738086000,
"exp": 1738089600
}
Подпишите заголовок и полезную нагрузку с помощью RS256 (RSA + SHA-256), используя закрытый ключ .pem, предоставленный Unico.
Любое поле, не указанное выше (например, sub, jti, nbf), вызовет ошибку 1.2.22. Используйте только перечисленные claims.
Запрос токена
Конечная точка токена одинакова для обоих контрактов:
| Среда | Конечная точка |
|---|---|
| Production | POST https://identity.acesso.io/oauth2/token |
| UAT | POST https://identityhomolog.acesso.io/oauth2/token |
| Параметр | Значение |
|---|---|
Content-Type | application/x-www-form-urlencoded |
grant_type | urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion | Ваш подписанный JWT |
- cURL
- Node.js
- Python
curl -X POST https://identity.acesso.io/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
-d "assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
import jwt from 'jsonwebtoken';
import fs from 'fs';
import qs from 'querystring';
const privateKey = fs.readFileSync('./private-key.pem');
const now = Math.floor(Date.now() / 1000);
const assertion = jwt.sign(
{
aud: 'https://identity.acesso.io',
scope: '*',
iat: now,
exp: now + 3600,
},
privateKey,
{ algorithm: 'RS256' }
);
const res = await fetch('https://identity.acesso.io/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: qs.stringify({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion,
}),
});
const { access_token, expires_in } = await res.json();
import time
import jwt # PyJWT
import requests
with open("private-key.pem", "rb") as f:
private_key = f.read()
now = int(time.time())
assertion = jwt.encode(
{
"aud": "https://identity.acesso.io",
"scope": "*",
"iat": now,
"exp": now + 3600,
},
private_key,
algorithm="RS256",
)
response = requests.post(
"https://identity.acesso.io/oauth2/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": assertion,
},
)
token_data = response.json()
access_token = token_data["access_token"]
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
| Поле | Тип | Описание |
|---|---|---|
access_token | string | JWT токен доступа. Используйте в Authorization: Bearer <token> во всех вызовах API. |
expires_in | integer | Время истечения срока действия в секундах. Пример: 3600. |
token_type | string | Всегда Bearer. |
Использование токена
Добавьте токен в заголовок Authorization каждого API-запроса. Заголовок одинаков для обоих контрактов — различается только хост и путь вызываемого API:
| Контракт | Production-хост | UAT-хост |
|---|---|---|
| Web & SDK | https://api.idcloud.unico.app | https://api.idcloud.uat.unico.app |
| API | https://api.id.unico.app | https://api.id.uat.unico.app |
Web & SDK — Authorization — единственный необходимый заголовок аутентификации:
curl -X POST https://api.idcloud.unico.app/client/v1/process \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
API — Authorization используется вместе с заголовком APIKEY:
curl -X POST https://api.id.unico.app/processes/v1 \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "APIKEY: $API_KEY" \
-H "Content-Type: application/json" \
-d '{ ... }'
Обновление токена
Токены истекают через 3600 секунд. Реализуйте упреждающее обновление на своём бэкенде:
- Отслеживайте
expires_inиз ответа с токеном и сохраняйте временную метку истечения. - Запрашивайте новый токен, когда до истечения остаётся 10 минут или меньше.
- Никогда не ждите
401в production для запуска обновления.
Справочник API
Полная спецификация OpenAPI для конечной точки токена доступна в authentication.yaml.
| Метод | Путь | Описание |
|---|---|---|
POST | /oauth2/token | Обмен подписанного JWT assertion на Bearer токен доступа |
Коды ошибок
| Код | Описание | Действие |
|---|---|---|
1.0.1 | ID, указанный в iss, некорректен | Убедитесь, что поле iss совпадает с Tenant ID, предоставленным при генерации закрытого ключа |
1.0.14 | Приложение неактивно | Уточните у менеджера проекта, активно ли используемое приложение |
1.1.1 | Параметр scope не указан | Добавьте "scope": "*" в полезную нагрузку JWT |
1.2.4 | JWT assertion недействителен | JWT assertion более не действителен. Две причины: (а) текущее время превышает exp (JWT действительно истёк — генерируйте новый assertion для каждого запроса токена); или (б) exp превышает iat + 3600 (срок действия слишком долгий — ограничьте exp значением iat + 3600). |
1.2.5 | Ошибка валидации JWT | JWT не удалось проверить. Проверьте параметры и убедитесь, что он подписан с помощью RS256 и правильного закрытого ключа |
1.2.6 | Закрытый ключ более недействителен | Закрытый ключ, использованный для подписи JWT, больше не принимается. Запросите новые учётные данные для аккаунта |
1.2.7 | JWT уже использован | JWT больше не принимается, так как уже был использован. Генерируйте новый assertion для каждого запроса токена |
1.2.11 | Аккаунт неактивен | Используемый аккаунт неактивен |
1.2.14 | Аккаунту не хватает необходимых разрешений | Используемый аккаунт не имеет необходимых разрешений |
1.2.18 | Аккаунт временно заблокирован | Аккаунт временно заблокирован из-за превышения числа неудачных попыток аутентификации |
1.2.19 | Несанкционированное олицетворение пользователя | JWT содержит claim sub, указывающий на аккаунт, которому не разрешено олицетворение. Удалите claim sub из полезной нагрузки. |
1.2.20 | Ошибка декодирования JWT | Не удалось декодировать JWT. Проверьте формат токена и убедитесь, что он подписан с помощью RS256. |
1.2.21 | Неверный закрытый ключ / Ошибка аутентификации | Подпись JWT не удалось проверить ни одним из известных ключей для этого аккаунта. Убедитесь, что вы используете правильный закрытый ключ .pem для данного сервисного аккаунта и среды. |
1.2.22 | Недопустимые поля в полезной нагрузке | JWT содержит лишние поля, которые не разрешены. Удалите все claims, не указанные в этом руководстве (например, sub, jti, nbf). Примечание: если вы включили claim sub и получили ошибку 1.2.19, эта ошибка имеет приоритет. |
1.3.1 | Ограничение доступа по IP | Ваш IP не включён в список разрешённых для этого аккаунта |
1.3.2 | Ограничение доступа по времени | Запрос выполнен вне допустимого временного окна для этого аккаунта |
Что дальше
- Среды — хосты sandbox и production
- Web & SDK — Создание процесса — первый вызов после аутентификации
- API — Создание процесса — первый вызов после аутентификации