Шаг 1 — Зарегистрируйте свой открытый ключ (одноразовая установка)
Создайте пару ключей RSA размером 4096 бит и поделитесь открытым ключом с Zonos. Это делается один раз при онбординге.
Создание пары ключей
# Генерируем приватный ключopenssl genrsa -out private_key.pem 4096 # Извлекаем открытый ключopenssl rsa -in private_key.pem -pubout -out public_key.pemПоделитесь public_key.pem с Zonos. Сохраните private_key.pem в специальный менеджер секретов (AWS Secrets Manager, HashiCorp Vault и т. д.) — никогда не сохраняйте в системе контроля версий или переменных окружения.
Zonos зарегистрирует ваш ключ и вернет ваш идентификатор организации, который становится утверждением iss во всех JWT-утверждениях.
Шаг 2 — Создайте JWT-утверждение
Подпишите JWT с помощью RS256, используя свой приватный ключ. Утверждение действительно для одного обмена токенами — сохраняйте окно истечения коротким (60–300 секунд).
Требуемые утверждения
| Утверждение↕ | Значение↕ |
|---|---|
iss | Ваш идентификатор организации Zonos (например "org_abc123") |
sub | Определяет вызывающий сервис (например "checkout-service") |
aud | Должно быть точно "zonos-auth" |
exp | Временная метка Unix; 60–300 секунд от iat |
iat | Временная метка Unix издания |
jti | Уникальный UUID для каждого утверждения (включает обнаружение воспроизведения) |
Заголовок JWT должен указывать "alg": "RS256" и "typ": "JWT".
Примеры кода
import jwt, uuid, time with open("private_key.pem") as f: private_key = f.read() now = int(time.time())assertion = jwt.encode( { "iss": "org_abc123", "sub": "checkout-service", "aud": "zonos-auth", "iat": now, "exp": now + 300, "jti": str(uuid.uuid4()), }, private_key, algorithm="RS256",)Шаг 3 — Обмен утверждением на маркер доступа
Отправьте подписанный JWT на конечную точку токена Zonos, чтобы получить краткосрочный токен Bearer.
Конечная точка
POST https://auth.zonos.com/oauth/token
Content-Type: application/json
Также принимается application/x-www-form-urlencoded.
Поля запроса
| Поле↕ | Требуется↕ | Значение↕ |
|---|---|---|
grant_type | Да | "urn:ietf:params:oauth:grant-type:jwt-bearer" |
assertion | Да | Ваш подписанный JWT (компактная сериализация) |
Запрос и ответ
{ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}| Поле ответа↕ | Описание↕ |
|---|---|
access_token | Токен Bearer для всех последующих запросов API |
token_type | Всегда "Bearer" |
expires_in | Секунды до истечения (по умолчанию: 300) |
scope | Разделенные пробелом разрешения, предоставленные этому токену |
Полные примеры кода
Шаг 4 — Вызовите API Zonos с маркером доступа
Включите токен доступа как токен Bearer в заголовке Authorization для каждого запроса к API Zonos.
Пример запроса
curl -X POST https://api.zonos.com/graphql \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "query": "{ ... }" }'Жизненный цикл токена и кеширование
Маркеры доступа по умолчанию истекают через 5 минут. Кешируйте токен и обновляйте его упреждающе — не запрашивайте новый токен при каждом вызове API. Каждое обновление требует вновь подписанного JWT-утверждения.
import time, requests _cache = {"access_token": None, "expires_at": 0} def get_access_token(): if time.time() < _cache["expires_at"] - 30: return _cache["access_token"] assertion = build_jwt_assertion() data = requests.post( "https://auth.zonos.com/oauth/token", json={ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": assertion, }, ).json() _cache["access_token"] = data["access_token"] _cache["expires_at"] = time.time() + data["expires_in"] return _cache["access_token"]Справочник ошибок
Все ошибки следуют формату ответа об ошибке OAuth 2.0 (RFC 6749 §5.2):
{ "error": "invalid_grant", "error_description": "JWT assertion has expired"}| HTTP Статус↕ | error↕ | Причина↕ |
|---|---|---|
400 | unsupported_grant_type | grant_type был не urn:ietf:params:oauth:grant-type:jwt-bearer |
400 | invalid_request | Отсутствует или неправильный формат поля |
401 | invalid_grant | Неверная подпись, истекшее утверждение, неизвестная организация или незарегистрированный ключ |
500 | server_error | Внутренняя ошибка — обратитесь в поддержку Zonos, если она сохраняется |
Распространенные причины invalid_grant:
expнаходится в прошлом — убедитесь, что ваши системные часы синхронизированы с NTPaudне является точно"zonos-auth"issне совпадает с вашим зарегистрированным идентификатором организации- Открытый ключ был ротирован, но еще не обновлен с Zonos
Лучшие практики безопасности
- Защитите свой приватный ключ. Сохраняйте его в специальном менеджере секретов — никогда не сохраняйте в системе контроля версий, переменных окружения или журналах.
- Сохраняйте утверждения краткосрочными. 60–300 секунд — это стандартно; нет причин выпускать более длительные.
- Включите
jti. Уникальное значение для каждого утверждения позволяет серверу обнаруживать воспроизведения. - Периодически ротируйте пары ключей. Зарегистрируйте новый открытый ключ с Zonos перед отзывом старого, чтобы избежать простоев.
- Никогда не логируйте значения
access_tokenилиassertion. Обращайтесь с обоими как с учетными данными.
Аутентификация OAuth 2.0
Аутентифицируйте свои серверные сервисы с помощью Zonos, используя асимметричную криптографию с открытым ключом — без общих секретов.
Zonos поддерживает аутентификацию между машинами через OAuth 2.0 JWT Bearer Token Grant (RFC 7523). Ваш сервис подписывает краткосрочный JWT своим приватным ключом RSA; Zonos проверяет его, используя ваш зарегистрированный открытый ключ, и возвращает токен Bearer в области вашей организации.
Краткое описание потока:
Authorization: Bearer <token>на каждый запрос API.