DOCS

Autenticación OAuth 2.0

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:

  1. Genere un par de claves RSA y registre su clave pública con Zonos.
  2. En tiempo de ejecución, firme una aserción JWT con su clave privada y envíela por POST al endpoint de token.
  3. Zonos devuelve un access token de corta duración.
  4. Incluya el access token como Authorization: Bearer <token> en cada solicitud a la API.

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 

1# Generate private key
2openssl genrsa -out private_key.pem 4096
3 
4 
5openssl rsa - private_key.pem -pubout -out public_key.pem

Comparta 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.

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 

ClaimValor
issSu Organization ID de Zonos (p. ej., "org_abc123")
subIdentifica el servicio que llama (p. ej., "checkout-service")
audDebe ser exactamente "zonos-auth"
expMarca de tiempo Unix; 60–300 segundos desde iat
iatMarca de tiempo Unix de emisión
jtiUUID único por aserción (habilita detección de repetición)

El encabezado JWT debe especificar "alg": "RS256" y "typ": "JWT".

Ejemplos de código 

1import jwt, uuid, time
2 
3with open("private_key.pem") as f:
4 private_key = f.read()
5 
6now = int(time.time())
7assertion = jwt.encode(
8 {
9 "iss": "org_abc123",
10 "sub": "checkout-service",
11 "aud": "zonos-auth",
12 "iat": now,
13 "exp": now + 300,
14 "jti": str(uuid.uuid4()),
15 },
16 private_key,
17 algorithm="RS256",
18)

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 

CampoObligatorioValor
grant_type"urn:ietf:params:oauth:grant-type:jwt-bearer"
assertionSu JWT firmado (serialización compacta)

Solicitud y respuesta 

1{
2 "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
3 "assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
4}
Campo de respuestaDescripción
access_tokenToken Bearer para todas las solicitudes posteriores a la API
token_typeSiempre "Bearer"
expires_inSegundos hasta la expiración (predeterminado: 300)
scopePermisos separados por espacios concedidos a este token

Ejemplos de código completos 

1import requests
2 
3response = requests.post(
4 "https://auth.zonos.com/oauth/token",
5 json={
6 "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
7 "assertion": assertion,
8 },
9)
10data = response.json()
11access_token = data["access_token"]
12expires_in = data["expires_in"]

Incluya el access token como token Bearer en el encabezado Authorization en cada solicitud a la API de Zonos.

Ejemplo de solicitud 

1curl -X POST https://api.zonos.com/graphql \
2 -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
3 -H "Content-Type: application/json" \
4 -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.

1import time, requests
2 
3_cache = {"access_token": None, "expires_at": 0}
4 
5def get_access_token():
6 if time.time() < _cache["expires_at"] - 30:
7 return _cache["access_token"]
8 
9 assertion = build_jwt_assertion()
10 data = requests.post(
11 "https://auth.zonos.com/oauth/token",
12 json={
13 "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
14 "assertion": assertion,
15 },
16 ).json()
17 
18 _cache["access_token"] = data["access_token"]
19 _cache["expires_at"] = time.time() + data["expires_in"]
20 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):

1{
2 "error": "invalid_grant",
3 "error_description": "JWT assertion has expired"
4}
Estado HTTPerrorCausa
400unsupported_grant_typegrant_type no era urn:ietf:params:oauth:grant-type:jwt-bearer
400invalid_requestCampo faltante o con formato incorrecto
401invalid_grantFirma no válida, aserción expirada, organización desconocida o clave no registrada
500server_errorError interno — contacte al soporte de Zonos si persiste

Causas comunes de invalid_grant:

  • exp está en el pasado — asegúrese de que el reloj de su sistema esté sincronizado con NTP
  • aud no es exactamente "zonos-auth"
  • iss no 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_token o assertion. Trátese ambos como credenciales.

¿Fue útil esta página?