Zugang & Schlüssel
Zwei Dinge müssen zusammenkommen, damit ein Aufruf funktioniert: die Schnittstelle muss für die Instanz freigeschaltet sein, und der Aufruf muss einen gültigen Zugangsschlüssel tragen.
Freischaltung
Die Schnittstelle ist nicht von vornherein aktiv.
- Ein Administrator öffnet Einstellungen → API und beschreibt kurz, wofür der Verein sie braucht.
- Der Antrag erscheint in der Instanz-Verwaltung im Reiter „API".
- Nach der Freigabe holt sich die Instanz den neuen Stand – spätestens nach fünf Minuten, mit Jetzt prüfen sofort.
Solange nichts freigeschaltet ist, antwortet jeder Pfad unter /api/v1 mit:
{ "error": { "code": "api_not_enabled", "message": "Die Schnittstelle ist für diese Instanz nicht freigeschaltet." } }
Ob ein Verein die Schnittstelle beantragt oder freigeschaltet hat, geht Fremde nichts an. Für einen Aufrufer ohne Freischaltung existiert dieser Pfad schlicht nicht.
Läuft die Anwendung selbst gehostet, entscheidet die Umgebungsvariable API_ENABLED=true.
Fällt die Instanz-Verwaltung aus, gilt der zuletzt bekannte Stand – ein Ausfall dort darf
nicht alle Kundenintegrationen abschalten.
Zugangsschlüssel
Schlüssel werden unter Einstellungen → API → Zugangsschlüssel vergeben.
Format
mv_a1b2c3d4_Xk7… mv_ + 8 Hex-Zeichen + _ + 43 Zeichen base64url
└┬┘ └───┬──┘ └─┬─┘
│ │ └─ das Geheimnis (32 Byte Zufall)
│ └──────── Präfix, steht auch in der Liste in der Anwendung
└─────────────── festes Kennzeichen für Secret-Scanner
Das Präfix mv_ ist Absicht: Werkzeuge wie Secret-Scanner erkennen daran einen
versehentlich in ein Repository geratenen Schlüssel.
Was mit dem Schlüssel passiert
| Regel | Warum |
|---|---|
| Der Klartext wird genau einmal angezeigt. Danach existiert nur noch sein SHA-256-Hash. | Ein Schlüssel, den der Server jederzeit wieder ausgeben könnte, wäre so viel wert wie der Zugriff auf die Datenbank. |
| Ablaufdatum ist Pflicht, höchstens 183 Tage. | Ein Schlüssel ohne Ablauf ist ein dauerhafter Generalschlüssel. Die Erneuerung sorgt dafür, dass vergessene Anbindungen auffallen. |
| 14 und 3 Tage vor Ablauf geht eine Mail an die Administratoren. | Damit die Anbindung nicht an einem Montagmorgen kommentarlos stehenbleibt. |
| Widerrufen statt löschen. | Der widerrufene Schlüssel bleibt in der Liste, damit im Aktivitätsprotokoll nachvollziehbar bleibt, welcher Schlüssel welche Änderung ausgelöst hat. |
32 Byte Zufall sind nicht zu erraten, und ein bcrypt-Hash wäre nicht indizierbar: jede einzelne Anfrage müsste gegen alle Schlüssel rechnen. Bei Passwörtern ist bcrypt richtig, hier nicht.
Anmeldung am Endpunkt
Jeder Aufruf trägt den Schlüssel im Kopf:
Authorization: Bearer mv_a1b2c3d4_Xk7…
Andere Wege gibt es nicht – kein Query-Parameter, kein Cookie, keine Basic-Auth. Ein Schlüssel in der URL landet in Server-Logs, Browser-Verläufen und Proxy-Protokollen.
/api/v1 erlaubt Anfragen von jeder Herkunft (CORS *, aber ohne Cookies). Das heißt
nicht, dass ein Schlüssel in JavaScript einer öffentlichen Website etwas zu suchen
hätte: Er stünde dort für jeden lesbar im Quelltext. Die Website ruft eine eigene
Serverfunktion, und die trägt den Schlüssel – nicht der Browser der Besucher.
Der erste Aufruf: /me
curl -H "Authorization: Bearer $KEY" https://deine-domain.de/api/v1/me
{
"data": {
"token": { "id": "8f2…", "name": "Website", "expires_at": "2027-02-14T00:00:00.000Z" },
"scopes": ["veranstaltungen:read", "gruppen:read", "warteliste:write"],
"rate_limit_per_minute": 120
}
}
/me braucht keinen Bereich – nur einen gültigen Schlüssel. Es ist der richtige
Aufruf, um eine Anbindung zu prüfen, und der einzige, der beantwortet, was ein Schlüssel
gerade wirklich darf: scopes ist die Schnittmenge aus den Bereichen des Schlüssels und
der Obergrenze des Vereins.
Die maschinenlesbare Beschreibung
curl -H "Authorization: Bearer $KEY" \
https://deine-domain.de/api/v1/openapi.json -o openapi.json
OpenAPI 3.1, direkt in Postman, Insomnia oder einen Code-Generator importierbar. Titel und Serveradresse tragen den Namen und die Domain der eigenen Instanz.
Im Browser aufgerufen antwortet /api/v1/openapi.json mit missing_token – ein Browser
kann keinen Authorization-Kopf mitschicken. Das ist gewollt: Die Datei beschreibt zwar
keine Daten, aber die gesamte Angriffsfläche. Also mit curl herunterladen und die Datei
lokal importieren.
Wenn etwas nicht funktioniert
| Antwort | Ursache | Abhilfe |
|---|---|---|
404 api_not_enabled | Nicht freigeschaltet | Antrag stellen bzw. in der Instanz-Verwaltung freigeben, dann Jetzt prüfen |
401 missing_token | Kein Authorization-Kopf | Header setzen – auch bei openapi.json |
401 invalid_token | Unbekannt oder widerrufen | Neuen Schlüssel erzeugen |
401 token_expired | Abgelaufen | Neuen Schlüssel erzeugen (max. 183 Tage) |
403 insufficient_scope | Bereich fehlt | Bereiche prüfen – erst die Obergrenze, dann den Schlüssel |
Abgelehnte Zugänge stehen im Server-Log (Bereich api-v1) mit Grund, Pfad und IP-Adresse.
Hat dies deine Frage beantwortet?