Schritt 1 — Öffentlichen Schlüssel registrieren (einmalige Einrichtung)
Generieren Sie ein 4096-Bit-RSA-Schlüsselpaar und teilen Sie den öffentlichen Schlüssel mit Zonos. Dies erfolgt einmalig während des Onboardings.
Schlüsselpaar generieren
Teilen Sie public_key.pem mit Zonos. Speichern Sie private_key.pem in einem dedizierten Secrets Manager (AWS Secrets Manager, HashiCorp Vault usw.) — niemals in der Quellcodeverwaltung oder in Umgebungsvariablen.
Zonos registriert Ihren Schlüssel und gibt Ihre Organization ID zurück, die zum iss-Claim in allen JWT-Assertions wird.
Schritt 2 — JWT-Assertion erstellen
Signieren Sie ein JWT mit RS256 unter Verwendung Ihres Privatschlüssels. Die Assertion ist für einen einzelnen Token-Austausch gültig — halten Sie das Ablauffenster kurz (60–300 Sekunden).
Erforderliche Claims
| Claim↕ | Value↕ |
|---|---|
iss | Your Zonos Organization ID (e.g. "org_abc123") |
sub | Identifies the calling service (e.g. "checkout-service") |
aud | Must be exactly "zonos-auth" |
exp | Unix timestamp; 60–300 seconds from iat |
iat | Unix timestamp of issuance |
jti | Unique UUID per assertion (enables replay detection) |
Der JWT-Header muss "alg": "RS256" und "typ": "JWT" angeben.
Codebeispiele
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",)Schritt 3 — Assertion gegen Access Token tauschen
Senden Sie das signierte JWT an den Zonos-Token-Endpunkt, um ein kurzlebiges Bearer-Token zu erhalten.
Endpunkt
POST https://auth.zonos.com/oauth/token
Content-Type: application/json
application/x-www-form-urlencoded wird ebenfalls akzeptiert.
Anfragefelder
| Field↕ | Required↕ | Value↕ |
|---|---|---|
grant_type | Yes | "urn:ietf:params:oauth:grant-type:jwt-bearer" |
assertion | Yes | Your signed JWT (compact serialization) |
Anfrage und Antwort
{ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}| Response field↕ | Description↕ |
|---|---|
access_token | Bearer token for all subsequent API requests |
token_type | Always "Bearer" |
expires_in | Seconds until expiry (default: 300) |
scope | Space-separated permissions granted to this token |
Vollständige Codebeispiele
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"]Schritt 4 — Zonos-APIs mit dem Access Token aufrufen
Fügen Sie das Access Token als Bearer-Token im Authorization-Header bei jeder Zonos-API-Anfrage hinzu.
Beispielanfrage
curl -X POST https://api.zonos.com/graphql \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "query": "{ ... }" }'Token-Lebenszyklus und Caching
Access Tokens laufen standardmäßig nach 5 Minuten ab. Cachen Sie das Token und erneuern Sie es proaktiv — fordern Sie nicht bei jedem API-Aufruf ein neues Token an. Jede Erneuerung erfordert eine neu signierte JWT-Assertion.
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"]Fehlerreferenz
Alle Fehler folgen dem OAuth 2.0-Fehlerantwortformat (RFC 6749 §5.2):
{ "error": "invalid_grant", "error_description": "JWT assertion has expired"}| HTTP Status↕ | 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 |
Häufige Ursachen für invalid_grant:
expliegt in der Vergangenheit — stellen Sie sicher, dass Ihre Systemuhr NTP-synchronisiert istaudist nicht exakt"zonos-auth"issstimmt nicht mit Ihrer registrierten Organization ID überein- Öffentlicher Schlüssel wurde rotiert, aber noch nicht bei Zonos aktualisiert
Sicherheits-Best Practices
- Schützen Sie Ihren Privatschlüssel. Speichern Sie ihn in einem dedizierten Secrets Manager — niemals in der Quellcodeverwaltung, Umgebungsvariablen oder Logs.
- Halten Sie Assertions kurzlebig. 60–300 Sekunden sind Standard; es gibt keinen Grund, längere auszustellen.
- Fügen Sie
jtihinzu. Ein eindeutiger Wert pro Assertion ermöglicht serverseitige Replay-Erkennung. - Rotieren Sie Schlüsselpaare regelmäßig. Registrieren Sie einen neuen öffentlichen Schlüssel bei Zonos, bevor Sie den alten widerrufen, um Ausfallzeiten zu vermeiden.
- Protokollieren Sie niemals
access_token- oderassertion-Werte. Behandeln Sie beides als Anmeldedaten.
OAuth 2.0-Authentifizierung
Authentifizieren Sie Ihre Backend-Services bei Zonos mit asymmetrischer Schlüsselkryptografie — ohne gemeinsame Geheimnisse.
Zonos unterstützt Machine-to-Machine-Authentifizierung über OAuth 2.0 JWT Bearer Token Grant (RFC 7523). Ihr Service signiert ein kurzlebiges JWT mit Ihrem RSA-Privatschlüssel; Zonos verifiziert es mit Ihrem registrierten öffentlichen Schlüssel und gibt ein Bearer-Token zurück, das auf Ihre Organisation beschränkt ist.
Ablaufübersicht:
Authorization: Bearer <token>bei jeder API-Anfrage hinzu.