OBS/Kostenpflichtige Module/RESTServer/Zugaenge
- A Preise aktualisieren
- C Personen übertragen
- E Kategorien verwalten
- G Kataloge verwalten
- I Merkliste übertragen
- K Varianten übertragen
- L Artikelvarianten übertragen
- M Referenzarten übertragen
- N Lagerbestände verwalten
- U Bestellungen einlesen
- V leere Passworte füllen
- W Update-Informationen zurücksetzen
- X Konfiguration
- Z Protokoll
Zugänge
Ein Zugang (Account) ist der Kanal, über den ein externer Konsument den REST-Server anspricht. Er bündelt API-Key, Host-Beschränkung, CORS-Konfiguration, optionale JWT-Authentifizierung und optionale mTLS-Subject-Prüfung.
Aufruf
Stammdaten -> Z Weitere Stammdaten -> REST-Server -> Zugänge
Felder
| Feld | Beschreibung |
|---|---|
| Name | Sprechender Name, erscheint im Protokoll und der Statistik |
| Aktiv | Inaktive Zugänge werden bei der Authentifizierung mit 403 abgewiesen |
| API-Key | Eindeutiger Schlüssel, den der Konsument im HTTP-Header apikey senden muss. Per Schlüsselsymbol generierbar |
| Host | Optionaler Hostname oder IP-Adresse des Konsumenten. Stimmt die anfragende IP nicht überein, wird mit 403 abgelehnt |
| CORS-Origins | Liste erlaubter Origins für Browser-Aufrufe, mehrere durch ; getrennt |
| mTLS-Subject | Erwartete RDN-Komponente(n) im Client-Zertifikat-Subject, Komma-/Semikolon-getrennt (alle müssen vorkommen; nur sinnvoll bei mTLS-Servern) |
| JWT | Schalter, ob für diesen Zugang ein JWT-Token nötig ist |
| JWT-Endpunkt | Pfad, über den der JWT-Token bezogen wird (z.B. oauth oder meineapp/dev/auth/login). Verglichen wird der vollständige Pfad, mehrstufige Angaben mit / sind also erlaubt |
| JWT-Key | Geheimer Schlüssel zur Signierung/Verifikation, per Schlüsselsymbol generierbar |
| JWT-Exp | Gültigkeitsdauer eines ausgestellten Access-Tokens in Minuten. Derselbe Wert wird dem Konsumenten in der Token-Antwort als expiresIn in Sekunden mitgeteilt und steht dem Endpunkt-Skript als _OBS_JWT_EXP_SEC zur Verfügung |
API-Key
Der API-Key ist die Basis-Authentifizierung. Der Client übergibt ihn im HTTP-Header:
apikey: abcd-efgh-ijkl-mnop-qrstuvwxyz12
Wird ein Aufruf ohne apikey-Header gestellt, sucht der Server intern nach einem Zugang mit API-Key * - damit lassen sich (mit Vorsicht!) auch öffentliche Endpunkte ohne Authentifizierung realisieren.
Host-Beschränkung
Ist im Feld Host ein Wert hinterlegt, akzeptiert der Server Anfragen unter diesem Zugang nur dann, wenn die Remote-IP exakt diesem Host entspricht oder durch DNS-Auflösung auf diese IP zeigt. DNS-Auflösungen werden 5 Minuten gecached.
CORS
Soll ein Endpunkt aus einer Browser-Anwendung (Single-Page-App, JavaScript) heraus aufgerufen werden, muss das Origin der Anwendung in der CORS-Liste des Zugangs eingetragen sein.
Format der Liste:
https://app.kunde.de;https://test.kunde.de;https://localhost:8080
Ablauf:
- Browser sendet einen Preflight-Request (OPTIONS). Der REST-Server prüft das Origin gegen die globale Origin-Liste aller Accounts (Cache, TTL 60s) und antwortet mit 204 + CORS-Header, falls erlaubt.
- Der eigentliche Request wird gegen die Origin-Liste des aktuell verwendeten Zugangs geprüft.
- Stimmt das Origin nicht, wird mit 403 Origin nicht erlaubt für Account ... abgelehnt.
Erlaubte Methoden: GET, POST, PUT, DELETE, PATCH. Erlaubte Header: Content-Type, apikey, Authorization, Accept. Diese Werte sind systemseitig festgelegt und werden in der Preflight-Antwort zurückgegeben.
JWT-Authentifizierung
Wird ein Zugang mit aktiver JWT-Pflicht aufgerufen, sind die folgenden Phasen zu durchlaufen (Phase 3 nur bei genutztem Refresh):
Phase 1: Token-Bezug
Der Konsument ruft den JWT-Endpunkt des Zugangs auf, z.B.:
POST https://api.meinserver.de/oauth/ Header: apikey: [API-KEY] Body: {"username":"...", "password":"..."}
Der Server führt das im Zugang hinterlegte Authentifizierungs-Skript aus (F7 in der Zugangs-Liste). Das Skript muss eine Funktion Authenticate bereitstellen, die ein JSON-Objekt mit:
- status = 1 bei Erfolg, 9 bei Misserfolg
- error = Fehlertext (bei status=9)
- _OBS_JWT_ID, _OBS_JWT_SUBJECT, _OBS_JWT_AUDIENCE für die JWT-Claims (optional)
- _OBS_JWT_CLAIM_<name> für beliebige Custom-Claims (z.B. Mandant tenant, Rollen roles); im Folge-Skript lesbar
- _OBS_JWT_REFRESH_ID (optional) löst die Ausstellung eines Refresh-Tokens aus; _OBS_JWT_REFRESH_EXP setzt dessen Lebensdauer in Minuten (Default 90 Tage)
zurückliefert. Bei Erfolg signiert der Server einen Token (HS256, Issuer OBS REST-Server, Lebenszeit gemäß JWT-Exp) und antwortet:
{"token": "eyJhbGciOi...",
"accessToken": "eyJhbGciOi...",
"expiresIn": 28800,
"serverTime": "2026-06-29T15:30:12+02:00"}
Zum Aufbau der Antwort:
- token und accessToken enthalten denselben Token. accessToken ist der Name, den die meisten Client-Bibliotheken erwarten; token bleibt für bestehende Konsumenten erhalten.
- expiresIn ist die Gültigkeit in Sekunden (JWT-Exp × 60).
- Alle weiteren Felder, die das Authenticate-Skript zurückgibt, werden mit ausgeliefert - mit Ausnahme von status und den _OBS_-Steuerfeldern. So kann das Skript z.B. eine Benutzer-Id, den Mandanten oder Rollen direkt in die Anmelde-Antwort legen, ohne dass der Client dafür einen zweiten Aufruf braucht.
Beispiel mit Zusatzfeldern aus dem Skript:
{"benutzerId": "4711", "tenant": "nord", "roles": ["TECHNIKER"],
"token": "eyJ...", "accessToken": "eyJ...", "refreshToken": "eyJ...",
"expiresIn": 28800, "serverTime": "2026-06-29T15:30:12+02:00"}
Mit der Ausstellung legt der Server zu dem Token-Paar eine Sitzungszeile in RESTSRV_TOKEN an. Lässt sich diese Zeile nicht schreiben (Tabelle fehlt, Datenbankproblem), wird kein Token ausgeliefert: der Server antwortet mit 503 und Retry-After. Das ist bewusst von der abgelehnten Anmeldung unterschieden - die Zugangsdaten waren in Ordnung, der Versuch darf wiederholt werden.
Wird die Anmeldung abgelehnt (status = 9), antwortet der Server mit 401 Unauthorized und reicht den Text aus dem Feld error als error.message an den Client durch - der Konsument kann ihn also direkt anzeigen. Die Formulierung liegt damit beim Skript.
Phase 2: Token-Verwendung
Bei allen folgenden Aufrufen sendet der Client den Token im Authorization-Header:
GET https://api.meinserver.de/kalender/v1 Header: apikey: [API-KEY] Authorization: Bearer eyJhbGciOi...
Der Server verifiziert Signatur, Issuer, Ausstellzeitpunkt und Ablauf (Toleranz: 20 Sekunden Clock-Skew) und prüft anschliessend die Sitzung in RESTSRV_TOKEN. Im Skript stehen die Claims als Parameter _OBS_JWT_ID, _OBS_JWT_SUBJECT und _OBS_JWT_AUDIENCE zur Verfügung.
Die Sitzungsprüfung weist ein Token ab, das zu keiner Zeile gehört oder dessen Sitzung gesperrt wurde - beides mit 401 und dem Code AUTH_EXPIRED. Der Grund steht jeweils im Protokoll RESTSRV_PROTO unter TokenStore: ....
wurde, gehört zu keiner Sitzung und wird abgewiesen. Nach dem Update müssen sich
angemeldete Konsumenten also einmalig neu anmelden.Phase 3: Token erneuern (Refresh)
Soll die App lange ohne Neuanmeldung arbeiten, stellt das Authenticate-Skript zusätzlich ein Refresh-Token aus (Feld _OBS_JWT_REFRESH_ID). Zum Erneuern ruft der Client denselben JWT-Endpunkt auf, aber mit dem Refresh-Token im Authorization-Header:
POST https://api.meinserver.de/oauth/ Header: apikey: [API-KEY] Authorization: Bearer eyJhbGciOi... (Refresh-Token)
Der Server erkennt am Bearer-Token den Refresh-Fall, verifiziert das Token (Signatur, Ablauf, token_use=refresh), entwertet es in der Sitzung und ruft erst dann im selben Skript die Methode Refresh auf. Das Skript liefert nur noch die aktuellen Claims zurück - Rotation, Einmalgebrauch und Sperrliste erledigt der Server. Die Antwort ist ein rotiertes Paar {"token","accessToken","refreshToken","expiresIn","serverTime"} in derselben Sitzung.
entfernt werden. Wer sie weiterführt, rotiert zweimal: einmal im Skript, einmal im Server. Der Server sieht die Skript-Tabelle nicht, und das Skript sieht die
Sitzung nicht.Verhalten bei einem bereits benutzten Refresh-Token:
| Lage | Antwort | Wirkung auf die Sitzung |
|---|---|---|
| Erneute Vorlage innerhalb von 60 Sekunden | 401 AUTH_EXPIRED | Keine. Das ist der Normalfall einer App, deren parallele Anfragen gleichzeitig in den Refresh laufen - eine gewinnt, die anderen sollen die vom Gewinner gespeicherten Token benutzen |
| Erneute Vorlage später | 401 AUTH_EXPIRED | Die gesamte Sitzung wird gesperrt. Das Token wurde kopiert oder wiederholt, ohne dass ein Gewinner es noch brauchen könnte; der Vorfall wird mit IP protokolliert |
Details und ein vollständiges Beispiel siehe Scripting.
Phase 4: Abmelden (Logout)
Ein Abmelden ist ein gewöhnlicher Endpunkt, der die Sitzung des vorgelegten Tokens sperrt. Dafür genügt ein Antwortfeld, das Skript braucht keine eigene Verwaltung:
function Post(oParams: TStrings; oBody: TJSONObject): string;
var oRes: TJSONObject;
begin
oRes := TJSONObject.Create();
try
oRes.AddPair('_OBS_JWT_REVOKE' , 'session'); // 'all' = alle Sitzungen des Benutzers
oRes.AddPair('_OBS_HTTP_STATUS', 204);
result := oRes.ToJSON();
finally
MyFreeAndNil(oRes);
end;
end;
- session sperrt die Sitzung des vorgelegten Tokens - einschliesslich aller vorherigen Rotationen, damit kein noch laufender Access-Token übrig bleibt.
- all sperrt alle Sitzungen desselben Subjects an diesem Zugang ("auf allen Geräten abmelden", Gerät verloren).
- Ein wiederholter Aufruf ist unschädlich und bleibt erfolgreich.
- Lässt sich die Sitzung nicht sperren, antwortet der Server mit 503 statt mit dem Erfolg des Skripts - ein Client darf nicht glauben, er sei abgemeldet, während sein Token weiterläuft.
gesetzt hat. Ohne Subject lässt sich die Menge der Sitzungen nicht bestimmen, und
der Aufruf antwortet mit 503.Sitzungen (RESTSRV_TOKEN)
Je ausgestelltem Token-Paar entsteht eine Zeile. Sie enthält die Sitzung, die Zeilenkennung, das Subject, die beiden Laufzeiten, IP und Trace-ID der Ausstellung sowie die Kennzeichen „verbraucht" und „gesperrt".
- Rotation und Widerruf sind getrennt. Ein Refresh entwertet nur das Refresh-Token; der zugehörige Access-Token bleibt bis zu seinem Ablauf gültig. Sonst bekämen parallel laufende Anfragen ein 401, obwohl niemand abgemeldet ist.
- Die Sitzung überlebt die Rotation. Alle Paare einer Anmeldung tragen dieselbe Sitzungskennung - deshalb kann ein Logout sie gemeinsam sperren.
- Aufräumen läuft automatisch beim Serverstart und danach höchstens stündlich. Gelöscht wird nur, was nichts mehr entscheiden kann: Zeilen, deren Access- und Refresh-Laufzeit vorbei sind. Eine verbrauchte Zeile bleibt bis dahin stehen, weil sonst die Erkennung eines später vorgelegten gestohlenen Refresh-Tokens verloren ginge.
- Kein Eingriff nötig. Die Tabelle wird nicht gepflegt; sie ist Diagnose-Material. Alle Abweisungen stehen als TokenStore: ... in RESTSRV_PROTO.
mTLS-Subject-Prüfung
Wird im Feld mTLS-Subject ein Wert hinterlegt, prüft der Server zusätzlich zur Standard-mTLS-Validierung, ob der Subject-DN des (CA-validierten) Client-Zertifikats die hinterlegten RDN-Komponenten enthält. Verglichen wird jede Komponente vollständig (kein Substring-Match) und case-insensitiv; mehrere Komponenten werden durch Komma oder Semikolon getrennt und müssen alle im Subject vorkommen.
Beispiele für Subject-Strings im Cert (OneLine-DN):
/C=DE/O=Kunde GmbH/CN=client-prod.kunde.de /C=DE/O=Kunde GmbH/CN=client-test.kunde.de
Mit CN=client-prod.kunde.de im Feld wird genau das prod-Cert akzeptiert, das test-Cert mit 401 abgewiesen. Da jede RDN-Komponente vollständig verglichen wird, matcht z.B. CN=client1 nicht fälschlich auch CN=client10. Mehrere Bedingungen lassen sich mit Komma/Semikolon kombinieren, z.B. O=Kunde GmbH;CN=client-prod.kunde.de.
Listen-Funktionen
In der Zugänge-Liste (allein):
- Einfg - neuer Zugang
- Return - Zugang bearbeiten
- F4 - Sortierung
- F7 - JWT-Authentifizierungs-Skript bearbeiten
- F8 - Statistik für den Zugang
Aus der Endpunkt-Liste via F6 geöffnet (Auswahl für Berechtigung):
- F2 - markierte Zugänge dem Endpunkt zuordnen
- F5 - Zugang in der Liste markieren / Markierung aufheben