Paso 1 — Registrar su clave pública (configuración única)
Genere un par de claves RSA de 4096 bits y comparta la clave pública con Zonos. Esto se hace una vez durante la incorporación.
Generar el par de claves
# Generate private keyopenssl genrsa -out private_key.pem 4096 openssl rsa - private_key.pem -pubout -out public_key.pemComparta public_key.pem con Zonos. Almacene private_key.pem en un gestor de secretos dedicado (AWS Secrets Manager, HashiCorp Vault, etc.) — nunca en control de versiones ni en variables de entorno.
Zonos registrará su clave y devolverá su Organization ID, que se convierte en el claim iss en todas las aserciones JWT.
Paso 2 — Crear una aserción JWT
Firme un JWT con RS256 utilizando su clave privada. La aserción es válida para un único intercambio de token — mantenga la ventana de expiración corta (60–300 segundos).
Claims requeridos
| Claim↕ | Valor↕ |
|---|---|
iss | Su Organization ID de Zonos (p. ej., "org_abc123") |
sub | Identifica el servicio que llama (p. ej., "checkout-service") |
aud | Debe ser exactamente "zonos-auth" |
exp | Marca de tiempo Unix; 60–300 segundos desde iat |
iat | Marca de tiempo Unix de emisión |
jti | UUID único por aserción (habilita detección de repetición) |
El encabezado JWT debe especificar "alg": "RS256" y "typ": "JWT".
Ejemplos de código
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",)Paso 3 — Intercambiar la aserción por un access token
Envíe el JWT firmado al endpoint de token de Zonos para recibir un token Bearer de corta duración.
Endpoint
POST https://auth.zonos.com/oauth/token
Content-Type: application/json
También se acepta application/x-www-form-urlencoded.
Campos de solicitud
| Campo↕ | Obligatorio↕ | Valor↕ |
|---|---|---|
grant_type | Sí | "urn:ietf:params:oauth:grant-type:jwt-bearer" |
assertion | Sí | Su JWT firmado (serialización compacta) |
Solicitud y respuesta
{ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}| Campo de respuesta↕ | Descripción↕ |
|---|---|
access_token | Token Bearer para todas las solicitudes posteriores a la API |
token_type | Siempre "Bearer" |
expires_in | Segundos hasta la expiración (predeterminado: 300) |
scope | Permisos separados por espacios concedidos a este token |
Ejemplos de código completos
import requests response = requests.post( "https://auth.zonos.com/oauth/token", json={ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": assertion, },)data = response.json()access_token = data["access_token"]expires_in = data["expires_in"]Paso 4 — Llamar a las API de Zonos con el access token
Incluya el access token como token Bearer en el encabezado Authorization en cada solicitud a la API de Zonos.
Ejemplo de solicitud
curl -X POST https://api.zonos.com/graphql \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "query": "{ ... }" }'Ciclo de vida del token y almacenamiento en caché
Los access tokens expiran en 5 minutos de forma predeterminada. Almacene el token en caché y renueve de forma proactiva — no solicite un token nuevo en cada llamada a la API. Cada renovación requiere una aserción JWT recién firmada.
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"]Referencia de errores
Todos los errores siguen el formato de respuesta de error de OAuth 2.0 (RFC 6749 §5.2):
{ "error": "invalid_grant", "error_description": "JWT assertion has expired"}| Estado HTTP↕ | error↕ | Causa↕ |
|---|---|---|
400 | unsupported_grant_type | grant_type no era urn:ietf:params:oauth:grant-type:jwt-bearer |
400 | invalid_request | Campo faltante o con formato incorrecto |
401 | invalid_grant | Firma no válida, aserción expirada, organización desconocida o clave no registrada |
500 | server_error | Error interno — contacte al soporte de Zonos si persiste |
Causas comunes de invalid_grant:
expestá en el pasado — asegúrese de que el reloj de su sistema esté sincronizado con NTPaudno es exactamente"zonos-auth"issno coincide con su Organization ID registrado- La clave pública fue rotada pero aún no se actualizó con Zonos
Mejores prácticas de seguridad
- Proteja su clave privada. Almacénela en un gestor de secretos dedicado — nunca en control de versiones, variables de entorno ni registros.
- Mantenga las aserciones de corta duración. 60–300 segundos es estándar; no hay razón para emitir aserciones más largas.
- Incluya
jti. Un valor único por aserción habilita la detección de repetición en el servidor. - Rote los pares de claves periódicamente. Registre una nueva clave pública con Zonos antes de revocar la anterior para evitar tiempo de inactividad.
- Nunca registre valores de
access_tokenoassertion. Trátese ambos como credenciales.
Autenticación OAuth 2.0
Autentique sus servicios backend con Zonos mediante criptografía de clave asimétrica — sin secretos compartidos.
Zonos admite autenticación de máquina a máquina mediante OAuth 2.0 JWT Bearer Token Grant (RFC 7523). Su servicio firma un JWT de corta duración con su clave privada RSA; Zonos lo verifica utilizando su clave pública registrada y devuelve un token Bearer con alcance a su organización.
Resumen del flujo:
Authorization: Bearer <token>en cada solicitud a la API.