Étape 1 — Enregistrer votre clé publique (configuration unique)
Générez une paire de clés RSA 4096 bits et partagez la clé publique avec Zonos. Cela se fait une fois lors de l'intégration.
Générer la paire de clés
openssl genrsa -out private_key.pem 4096 openssl rsa - private_key.pem -pubout -out public_key.pemPartagez public_key.pem avec Zonos. Stockez private_key.pem dans un gestionnaire de secrets dédié (AWS Secrets Manager, HashiCorp Vault, etc.) — jamais dans le contrôle de source ou les variables d'environnement.
Zonos enregistrera votre clé et renverra votre Organization ID, qui devient la revendication iss dans toutes les assertions JWT.
Étape 2 — Construire une assertion JWT
Signez un JWT avec RS256 en utilisant votre clé privée. L'assertion est valide pour un seul échange de jeton — gardez une fenêtre d'expiration courte (60–300 secondes).
Revendications requises
| Revendication↕ | Valeur↕ |
|---|---|
iss | Votre Organization ID Zonos (par ex. "org_abc123") |
sub | Identifie le service appelant (par ex. "checkout-service") |
aud | Doit être exactement "zonos-auth" |
exp | Horodatage Unix ; 60–300 secondes après iat |
iat | Horodatage Unix d'émission |
jti | UUID unique par assertion (permet la détection de rejeu) |
L'en-tête JWT doit spécifier "alg": "RS256" et "typ": "JWT".
Exemples de code
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",)Étape 3 — Échanger l'assertion contre un jeton d'accès
Envoyez le JWT signé au point de terminaison de jeton Zonos pour recevoir un jeton Bearer à courte durée de vie.
Point de terminaison
POST https://auth.zonos.com/oauth/token
Content-Type: application/json
application/x-www-form-urlencoded est également accepté.
Champs de requête
| Champ↕ | Requis↕ | Value↕ |
|---|---|---|
grant_type | Oui | "urn:ietf:params:oauth:grant-type:jwt-bearer" |
assertion | Oui | Votre JWT signé (sérialisation compacte) |
Requête et réponse
{ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}| Champ de réponse↕ | Description↕ |
|---|---|
access_token | Jeton Bearer pour toutes les requêtes API suivantes |
token_type | Toujours "Bearer" |
expires_in | Secondes avant expiration (par défaut : 300) |
scope | Permissions séparées par des espaces accordées à ce jeton |
Exemples de code complets
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"]Étape 4 — Appeler les API Zonos avec le jeton d'accès
Incluez le jeton d'accès comme jeton Bearer dans l'en-tête Authorization sur chaque requête API Zonos.
Exemple de requête
curl -X POST https://api.zonos.com/graphql \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "query": "{ ... }" }'Cycle de vie et mise en cache des jetons
Les jetons d'accès expirent par défaut après 5 minutes. Mettez le jeton en cache et actualisez de manière proactive — ne demandez pas un nouveau jeton à chaque appel API. Chaque actualisation nécessite une nouvelle assertion JWT signée.
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"]Référence des erreurs
Toutes les erreurs suivent le format de réponse d'erreur OAuth 2.0 (RFC 6749 §5.2) :
{ "error": "invalid_grant", "error_description": "JWT assertion has expired"}| Statut HTTP↕ | error↕ | Cause↕ |
|---|---|---|
400 | unsupported_grant_type | grant_type was not urn:ietf:params:oauth:grant-type:jwt-bearer |
400 | invalid_request | Missing or malformed field |
401 | invalid_grant | Invalid signature, expired assertion, unknown org, or unregistered key |
500 | server_error | Internal error — contact Zonos support if persistent |
Causes courantes de invalid_grant :
expest dans le passé — assurez-vous que l'horloge système est synchronisée NTPaudn'est pas exactement"zonos-auth"issne correspond pas à votre Organization ID enregistré- La clé publique a été renouvelée mais pas encore mise à jour auprès de Zonos
Bonnes pratiques de sécurité
- Protégez votre clé privée. Stockez-la dans un gestionnaire de secrets dédié — jamais dans le contrôle de source, les variables d'environnement ou les journaux.
- Gardez les assertions à courte durée de vie. 60–300 secondes est la norme ; il n'y a aucune raison d'en émettre de plus longues.
- Incluez
jti. Une valeur unique par assertion permet la détection de rejeu côté serveur. - Renouvelez les paires de clés périodiquement. Enregistrez une nouvelle clé publique auprès de Zonos avant de révoquer l'ancienne pour éviter les interruptions.
- Ne journalisez jamais les valeurs
access_tokenouassertion. Traitez les deux comme des identifiants.
Authentification OAuth 2.0
Authentifiez vos services backend avec Zonos via la cryptographie à clé asymétrique — sans secrets partagés.
Zonos prend en charge l'authentification machine à machine via OAuth 2.0 JWT Bearer Token Grant (RFC 7523). Votre service signe un JWT à courte durée de vie avec votre clé privée RSA ; Zonos le vérifie à l'aide de votre clé publique enregistrée et renvoie un jeton Bearer limité à votre organisation.
Résumé du flux :
Authorization: Bearer <token>sur chaque requête API.