Zum Inhalt

Auth-Flow

Schritt 1 — Login

curl -X POST https://deine-domain.tld/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"..."}'

Response (ohne 2FA)

{
  "access_token": "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "token_type": "bearer",
  "expires_in": 86400
}

Response (mit 2FA)

{
  "two_fa_required": true,
  "challenge_token": "tx_..."
}

Server hat eine 2FA-Code-Mail verschickt. Mit dem challenge_token weiter:

Schritt 2 — 2FA verifizieren

curl -X POST https://deine-domain.tld/api/v1/auth/2fa/verify \
  -H "Content-Type: application/json" \
  -d '{"challenge_token":"tx_...","code":"12345678"}'

Response

{
  "access_token": "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "expires_in": 86400
}

Bei falschem Code: 401 + attempts_remaining im Body. Nach 5 Fehlversuchen: 429 + Retry-After: 1800.

Schritt 3 — Anfragen mit JWT

curl https://deine-domain.tld/api/v1/hosts \
  -H "Authorization: Bearer eyJhbGc..."

Refresh

curl -X POST https://deine-domain.tld/api/v1/auth/refresh \
  -H "Authorization: Bearer <refresh_token>"

Liefert ein neues access_token (und neues refresh_token). Refresh-Token ist Single-Use.

Logout

curl -X POST https://deine-domain.tld/api/v1/auth/logout \
  -H "Authorization: Bearer <access_token>"

Server invalidiert den Refresh-Token, Frontend wirft den Access-Token weg.

Personal-Access-Tokens (PATs)

Alternative für CLI/Scripts ohne Browser-Login:

curl -X POST https://deine-domain.tld/api/v1/auth/api-keys \
  -H "Authorization: Bearer <jwt>" \
  -d '{
    "name":"deploy-script",
    "scope":"read_write",
    "expires_at":"2027-01-01T00:00:00Z"
  }'

Response enthält den Klartext-Token genau einmal. Speichern.

Nutzung:

curl https://deine-domain.tld/api/v1/hosts \
  -H "Authorization: Bearer <pat>"

PATs sind funktional identisch zu User-JWTs — gleiche Permissions, gleiche Tenant-Bindung.

Permission-Failures

Bei fehlender Permission:

{
  "detail": {
    "error": "permission_denied",
    "missing": "host.delete"
  }
}

HTTP-Status 403.

Tenant-Scope

JWT enthält tenant_id (eigener Tenant) und tenant_scope (null für Super-Admin, sonst Tenant-UUID).

Cross-Tenant-Anfragen (Super-Admin) optional via Query: ?tenant_id=<uuid>. Ohne Query bekommst du den eigenen Tenant.

Rate-Limits

  • Login/2FA: 10 req/min pro IP
  • Sonstige Endpoints: 600 req/min pro User

Bei Überschreitung: 429 + Retry-After.

Zeit-Sync

JWT exp-Claim setzt voraus, dass Client und Server zeitsynchron sind (Default: 30 s Toleranz). Wenn Server-Zeit falsch (kein NTP), gibt es phantome 401-Fehler.

Anschluss