API Keys API
API-Keys sind rollenbasierte Maschinen-Identitäten für externe Systeme (Server-zu-Server). Ein API-Key authentifiziert über den Header X-API-Key und erhält die Rechte der ihm zugewiesenen Rolle — er durchläuft dieselbe RBAC-Matrix wie ein eingeloggter Benutzer (Unified Actor). Verwaltet werden Keys unter /api/api-keys; das ist eine reine Admin-Funktion und nur mit einem eingeloggten Benutzer möglich.
Authentifizierung & Permissions
Es gibt zwei getrennte Ebenen: die VERWALTUNG der Keys (/api/api-keys) und die NUTZUNG eines Keys gegen die normalen API-Routen.
| Aktion | Permission |
|---|---|
| Alle Verwaltungs-Routen (lesen/erstellen/ändern/löschen/aktivieren) | settings.manageRoles |
| Einen Key nutzen (gegen API-Routen) | Rechte der zugewiesenen Rolle |
User-Kontext erforderlich (kein API-Key): Sämtliche /api/api-keys-Routen verlangen einen eingeloggten Benutzer UND settings.manageRoles. Ein X-API-Key wird hier mit 403 abgewiesen — ein API-Key kann sich also nicht selbst oder andere Keys verwalten.
Unified Actor: Bei der Nutzung gelten die Rechte der Rolle des Keys, geprüft genau wie bei angemeldeten Benutzern. Ist dem Key keine aktive Rolle zugewiesen, wird jede Anfrage mit 403 API_KEY_NO_ROLE abgewiesen. Details: Permissions & RBAC.
Endpoints Übersicht
Alle Routen: settings.manageRoles + eingeloggter Benutzer.
| Method | Endpoint | Beschreibung |
|---|---|---|
GET | /api/api-keys | Liste aller Keys (ohne Klartext-Key, neueste zuerst) |
POST | /api/api-keys | Key erstellen (201; Klartext-Key NUR hier sichtbar) |
PUT | /api/api-keys/:id | Key aktualisieren |
DELETE | /api/api-keys/:id | Key endgültig löschen |
POST | /api/api-keys/:id/deactivate | Key deaktivieren (isActive=false, umkehrbar) |
POST | /api/api-keys/:id/reactivate | Key wieder aktivieren |
Deaktivieren über POST /:id/deactivate; alternativ lässt sich isActive per PUT /:id setzen.
Felder
| Feld | Typ | Beschreibung |
|---|---|---|
name | String (1–100) | Anzeigename, eindeutig (Duplikat → 409) |
description | String? (≤500) | Optionale Beschreibung |
roleId | String? | Zugewiesene Rolle — bestimmt die Rechte des Keys. Wird die Rolle gelöscht, wird das Feld auf null gesetzt. |
allowedIPs | String[] | IP-Whitelist (einzelne IPv4/IPv6 oder CIDR, z.B. 10.0.0.0/24). Leer = von überall nutzbar. |
rateLimit | Int? (1–10000) | Max. Requests pro Minute. null = unbegrenzt. |
expiresAt | DateTime? (ISO 8601) | Ablaufdatum. Abgelaufene Keys werden bei Nutzung mit 403 abgewiesen. |
isActive | Boolean | Aktiv-Status. Bei Create immer true; nur per Update / (de)activate änderbar. |
key | String | Nur im Response. Gespeichert wird ein SHA-256-Hash; der Klartext (Präfix apk_) wird ausschließlich bei der Erstellung zurückgegeben. |
keyPreview | String | Erste 12 Zeichen für die Anzeige (z.B. apk_Ab12Cd34…) |
roleName | String? | Nur im Response: Anzeigename der Rolle (aus roleId aufgelöst) |
lastUsedAt | DateTime? | Nur im Response: Zeitpunkt der letzten Nutzung (bei jedem Request aktualisiert) |
Key erstellen
POST /api/api-keys
{
"name": "SAP Integration",
"description": "API key for SAP ticket sync",
"roleId": "clx-integration-role",
"rateLimit": 1000,
"allowedIPs": ["192.168.1.100", "10.0.0.0/24"],
"expiresAt": "2027-12-31T23:59:59Z"
}
Response (201 Created)
{
"success": true,
"message": "API key created successfully. Save this key - it will not be shown again!",
"apiKey": {
"id": "clx...",
"name": "SAP Integration",
"key": "apk_8sJ2...full-plaintext-key-only-shown-once...",
"description": "API key for SAP ticket sync",
"isActive": true,
"rateLimit": 1000,
"createdAt": "2026-06-18T10:00:00Z",
"expiresAt": "2027-12-31T23:59:59Z",
"roleId": "clx-integration-role",
"roleName": "Integration",
"allowedIPs": ["192.168.1.100", "10.0.0.0/24"]
}
}
WICHTIG: Der vollständige Klartext-Key (key) wird NUR EINMAL bei der Erstellung zurückgegeben. Danach liefern alle Endpoints nur noch keyPreview (erste 12 Zeichen). Key sofort sicher speichern!
Key verwenden
Der Key wird im Header X-API-Key gesendet (nicht als Bearer-Token):
curl https://your-instance.com/api/tickets \
-H "X-API-Key: apk_8sJ2...your-key..."
Laufzeit-Prüfungen (in dieser Reihenfolge)
| Prüfung | Fehlschlag |
|---|---|
| Header X-API-Key vorhanden | 401 API_KEY_REQUIRED |
| Key existiert (SHA-256-Lookup) | 401 INVALID_API_KEY |
isActive | 403 API_KEY_DISABLED |
| Nicht abgelaufen (expiresAt) | 403 API_KEY_EXPIRED |
| Client-IP in allowedIPs (falls gesetzt) | 403 IP_NOT_ALLOWED |
| Rate-Limit nicht überschritten (falls gesetzt) | 429 RATE_LIMIT_EXCEEDED (+ Retry-After) |
Das Rate-Limit zählt in einem 60-Sekunden-Fenster. Ist der Zählerspeicher (Redis) nicht erreichbar, werden Key-Requests mit 503 SERVICE_UNAVAILABLE (+ Retry-After) abgewiesen, damit das Limit nicht unkontrolliert entfällt. Die IP-Prüfung versteht CIDR-Bereiche und normalisiert IPv4-mapped-IPv6 (::ffff:…).
Fehlercodes
| HTTP | Error Code | Beschreibung |
|---|---|---|
| 400 | — | Validierungsfehler (z.B. ungültige IP/CIDR, ungültiges Datumsformat, rateLimit außerhalb 1–10000) |
| 403 | FORBIDDEN | settings.manageRoles fehlt oder kein User-Kontext (X-API-Key) |
| 404 | API_KEY_NOT_FOUND | Key existiert nicht |
| 409 | API_KEY_NAME_EXISTS | Ein Key mit diesem Namen existiert bereits |
Die Codes 401/403/429/503 in der Tabelle „Laufzeit-Prüfungen" betreffen die NUTZUNG eines Keys; die obigen Codes betreffen die VERWALTUNG.
Sicherheit & Best Practices
- Nur für Server-zu-Server-Integrationen verwenden, nie im Browser/Frontend.
- Rolle nach dem Least-Privilege-Prinzip wählen — der Key erhält genau deren Rechte.
- IP-Whitelist und Ablaufdatum setzen; Rate-Limit gegen Missbrauch konfigurieren.
- Keys rotieren (alten deaktivieren, neuen erstellen) und sicher (Secret-Store) ablegen.
- Alle Key-Aktionen (Create/Update/Delete/(De)aktivieren) werden im Audit-Log (Domain SECURITY) protokolliert.