Authentifizierung
API-Key-Typen, Scopes, Origin-Allowlists, Rotation und wie du Rate-Limit- und Quota-Header liest.
Jeder Request an https://wohno.de/api/v1/* wird über einen API-Key im
X-API-Key-Header authentifiziert. Es gibt zwei Key-Typen — die Wahl des
richtigen ist die wichtigste Authentifizierungs-Entscheidung, die du triffst.
Publishable- vs. Secret-Keys
| Präfix | Typ | Verwendung | Erlaubte Scopes |
|---|---|---|---|
sk_live_* | Secret | Server-zu-Server | Jeder Scope (inkl. write / delete / *) |
pk_live_* | Publishable | Browser / Embed | Read-only-Whitelist (siehe unten) |
sk_test_* / pk_test_* existieren für Sandbox-Setups.
Wann welcher
- Secret (
sk_) — überall dort, wo der Key geheim bleiben kann: Backends, Cron-Jobs, CRM-Sync, Server-zu-Server-Integrationen. Er darf lesen, schreiben und löschen. Ein Secret Key wird nur als bcrypt-Hash gespeichert und genau einmal im Klartext zurückgegeben — kopiere ihn beim Erstellen. - Publishable (
pk_) — überall dort, wo der Key im Browser landet: Embed-Widgets, öffentliches HTML, clientseitiges JS. Er darf nur die Read-only-Whitelist tragen und muss eine Origin-Allowlist haben. Publishable Keys sind bewusst browser-sicher: Ihre Sicherheit kommt aus der Scope-Whitelist plus der Origin-Allowlist, nicht aus der Geheimhaltung.
Faustregel: Wenn ein Wert jemals einen Browser erreicht, muss es ein
pk_-Key sein. Packe niemals einen Secret Key in ein Frontend-Bundle.
Scopes
Scopes folgen dem Format resource:action (z. B. listings:read) und sind
hierarchisch:
*gewährt Vollzugriff.resource:*gewährt alle Aktionen auf dieser Ressource.deleteimpliziertwrite, undwriteimpliziertread.
Ein fehlender Scope liefert 403 INSUFFICIENT_SCOPE. Die vollständige
Scope-Registry findest du in der
Konventions-Referenz.
Publishable-Whitelist
Ein pk_-Key darf nur diese Read-Scopes tragen:
organizations:readlistings:readembed:readappointments:readappointments:book
Das wird zweifach durchgesetzt (Defense-in-Depth): in der Applikationsschicht und durch einen Datenbank-Trigger.
Origin- und IP-Allowlists
- Die Origin-Allowlist ist für
pk_-Keys Pflicht und fürsk_-Keys optional.- Subdomain-Wildcards wie
https://*.example.commatchen genau eine Subdomain-Ebene. - HTTPS ist Pflicht (außer
http://localhost). - Browser senden den
Origin-Header automatisch. Fehlt er bei einempk_-Call, ist der Request fehlerhaft und liefert403 ORIGIN_REQUIRED. - Ein Origin, der zu keinem Allowlist-Eintrag passt, liefert
403 ORIGIN_NOT_ALLOWED.
- Subdomain-Wildcards wie
- Die IP-Allowlist ist nur für
sk_-Keys sinnvoll (IPv4 + IPv4-CIDR, max. 10 Einträge). Empfohlen für produktive Server-zu-Server-Keys. Ein Request von einer IP außerhalb der Liste liefert403 IP_NOT_ALLOWED.
Key-Rotation
Rotiere einen Key ohne Downtime über eine Overlap-Periode:
- Ein neuer Key wird mit dem gleichen Profil erstellt (Typ, Scopes, Allowlists); sein Roh-Wert wird einmal zurückgegeben.
- Der alte Key erhält ein
rotation_expires_at = now() + overlapDays(Standard 7 Tage, 1–30 erlaubt). - Beide Keys validieren während des Overlap-Fensters — rolle den neuen Key aus und mottet dann den alten ein.
- Nach dem Fenster liefert der alte Key
401 KEY_ROTATED_OUTund wird von einem nächtlichen Cleanup-Job widerrufen.
Empfehlung: alle 90 Tage rotieren; ein 7-Tage-Overlap reicht für ein Deployment.
Rate-Limit- und Quota-Header
Jede /api/v1/*-Antwort trägt informative Header, mit denen du dich selbst
drosseln kannst.
Rate-Limits (pro Key, 1000 req/h)
| Header | Bedeutung | Beispiel |
|---|---|---|
X-RateLimit-Limit | Max. Requests im Fenster | 1000 |
X-RateLimit-Remaining | Verbleibende Requests im aktuellen Fenster | 950 |
X-RateLimit-Reset | ISO-Zeit, wann das Fenster zurückgesetzt wird | 2026-06-03T11:00:00.000Z |
Retry-After | Sekunden bis zum nächsten erlaubten Request (nur 429) | 42 |
Überschreiten des Limits liefert 429 RATE_LIMITED. Nutze exponentielles
Backoff und respektiere Retry-After.
Quotas (pro Organisation, monatlich)
| Header | Bedeutung | Beispiel |
|---|---|---|
X-Quota-Limit | Monatliches Plan-Limit oder unlimited | 10000 |
X-Quota-Used | Aktueller Monatszähler oder unknown | 3450 |
X-Quota-Reset | ISO-Zeit des Monats-Resets (Europe/Berlin) | 2026-07-01T00:00:00.000Z |
X-Quota-Status | ok / soft-warning / unavailable | soft-warning |
soft-warning wird ab ≥ 80 % Nutzung gesetzt. Quotas sind standardmäßig nur
Tracking; sobald sie durchgesetzt werden, liefert eine Überschreitung
429 QUOTA_EXCEEDED.
Authentifizierungs-Fehler
| HTTP | Code | Wann |
|---|---|---|
| 401 | UNAUTHORIZED | X-API-Key-Header fehlt komplett |
| 401 | INVALID_API_KEY | Key unbekannt, widerrufen oder abgelaufen |
| 401 | KEY_ROTATED_OUT | Rotierter Key nach Ablauf des Overlap-Fensters genutzt |
| 403 | INSUFFICIENT_SCOPE | Key fehlt der erforderliche Scope |
| 403 | ORIGIN_REQUIRED | pk_-Key ohne Origin-Header aufgerufen |
| 403 | ORIGIN_NOT_ALLOWED | Origin nicht in der Allowlist des Keys |
| 403 | IP_NOT_ALLOWED | Client-IP nicht in der Allowlist des Keys |
Verzweige über den stabilen error.code-String, niemals über die
menschenlesbare message.
Referenz
Die kanonischen, code-verifizierten Details zu Authentifizierung, Scopes, Fehlerformaten und Headern findest du in der API-Konventions-Referenz.