Skip to Content

Actions-Engine-API

Actions sind benutzerdefinierte JavaScript-Code-Snippets, die an bestimmten Punkten während Authentifizierungsflows ausgeführt werden. Sie ermöglichen es, Auris mit benutzerdefinierter Logik zu erweitern, ohne die Kernplattform zu modifizieren: Tokens mit externen Daten anreichern, verdächtige Registrierungen blockieren, benutzerdefinierte Passwortrichtlinien erzwingen oder Benutzerdaten mit externen Systemen synchronisieren.

Actions werden in einer Sandbox-Umgebung mit eingeschränktem Scope ausgeführt. Jede Action ist mit einem Triggerpunkt (z.B. post_login) verknüpft und wird in Prioritätsreihenfolge ausgeführt. Mehrere Actions können demselben Trigger zugewiesen sein.

Alle Actions-Endpunkte erfordern den x-tenant-Header. Das Erstellen und Verwalten von Actions erfordert Admin-Zugriff (impliziert durch die admin:all-Berechtigung oder die manage:actions-Berechtigung).

Action-Lebenszyklus

  1. Eine Action mit einem Triggertyp und JavaScript-Code erstellen.
  2. Die Action durch Überprüfung der Ausführungsprotokolle testen.
  3. Den Status der Action auf active setzen, um sie in der Produktion zu aktivieren.
  4. Ausführung über den Protokollendpunkt überwachen.

Action-CRUD

Actions auflisten

GET/api/actionsRequires: manage:actions

Alle Actions für den Tenant auflisten. Gibt Action-Metadaten zurück, einschließlich Triggertyp, Status, Ausführungsstatistiken und Reihenfolge. Actions werden in aufsteigender Reihenfolge des order-Felds für jeden Triggertyp ausgeführt.

Abfrageparameter

ParameterTypBeschreibung
pageintegerSeitennummer (Standard: 1)
limitintegerElemente pro Seite (Standard: 20)
triggerstringNach Triggertyp filtern (z.B. post_login)
statusactive | inactiveNach Status filtern

Erfolgsantwort

{ "ok": true, "data": { "data": [ { "id": "act_abc123", "name": "Token mit CRM-Daten anreichern", "trigger": "post_login", "status": "active", "order": 1, "timeout": 5000, "executionCount": 14523, "errorCount": 12, "lastExecutedAt": "2025-02-18T09:50:00Z", "createdAt": "2025-01-10T10:00:00Z", "updatedAt": "2025-02-15T14:00:00Z" }, { "id": "act_def456", "name": "Wegwerf-E-Mails blockieren", "trigger": "pre_signup", "status": "active", "order": 1, "timeout": 3000, "executionCount": 892, "errorCount": 0, "lastExecutedAt": "2025-02-18T08:30:00Z", "createdAt": "2025-01-20T10:00:00Z", "updatedAt": "2025-01-20T10:00:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 } } }

Action erstellen

POST/api/actionsRequires: manage:actions

Eine neue Action erstellen. Die Action wird standardmäßig mit dem Status inactive erstellt. Setze sie nach dem Testen über den Toggle-Endpunkt auf active. Der JavaScript-Code wird vor der Speicherung auf blockierte Muster überprüft.

Anforderungs-Body

{ "name": "Token mit CRM-Daten anreichern", "trigger": "post_login", "code": "async function handler(context, api) {\n const response = await api.fetch('https://crm.example.com/api/user', {\n headers: { 'X-User-Email': context.user.email }\n });\n const crmData = await response.json();\n api.setCustomClaim('crm_id', crmData.id);\n api.setCustomClaim('account_tier', crmData.tier);\n}", "order": 1, "timeout": 5000 }
FeldTypErforderlichBeschreibung
namestringJaMenschenlesbarer Name
triggerstringJaTriggerpunkt (siehe Triggertypen)
codestringJaJavaScript-Funktionskörper
orderintegerNeinAusführungsreihenfolge innerhalb des Triggers (Standard: 0, kleiner = zuerst)
timeoutintegerNeinMaximale Ausführungszeit in Millisekunden (Standard: 5000, max: 10000)

Erfolgsantwort

{ "ok": true, "data": { "id": "act_ghi789", "name": "Token mit CRM-Daten anreichern", "trigger": "post_login", "status": "inactive", "code": "async function handler(context, api) { ... }", "order": 1, "timeout": 5000, "executionCount": 0, "errorCount": 0, "createdAt": "2025-02-18T10:00:00Z" } }

Fehlercodes

CodeHTTPBeschreibung
VALIDATION_ERROR400Fehlende Pflichtfelder oder ungültiger Triggertyp
BLOCKED_PATTERN400Code enthält ein blockiertes Muster (siehe Sandbox-Einschränkungen)
CODE_TOO_LARGE400Code überschreitet die maximal zulässige Größe

Action abrufen

GET/api/actions/[id]Requires: manage:actions

Eine einzelne Action anhand ihrer ID abrufen, einschließlich ihres vollständigen Codes und der Ausführungsstatistiken.

Erfolgsantwort

{ "ok": true, "data": { "id": "act_abc123", "name": "Token mit CRM-Daten anreichern", "trigger": "post_login", "status": "active", "code": "async function handler(context, api) {\n const response = await api.fetch('https://crm.example.com/api/user', {\n headers: { 'X-User-Email': context.user.email }\n });\n const crmData = await response.json();\n api.setCustomClaim('crm_id', crmData.id);\n api.setCustomClaim('account_tier', crmData.tier);\n}", "order": 1, "timeout": 5000, "executionCount": 14523, "errorCount": 12, "lastExecutedAt": "2025-02-18T09:50:00Z", "createdAt": "2025-01-10T10:00:00Z", "updatedAt": "2025-02-15T14:00:00Z" } }

Action aktualisieren

PUT/api/actions/[id]Requires: manage:actions

Den Namen, Code, Trigger, die Reihenfolge oder das Timeout einer Action aktualisieren. Alle Felder sind optional — nur bereitgestellte Felder werden aktualisiert. Aktualisierter Code wird erneut auf blockierte Muster überprüft.

Anforderungs-Body

{ "name": "Token mit CRM-Daten anreichern v2", "code": "async function handler(context, api) {\n // Aktualisierte Logik\n const data = await api.fetch('https://crm.example.com/v2/user/' + context.user.id);\n const user = await data.json();\n api.setCustomClaim('crm_id', user.id);\n}", "timeout": 8000 }

Erfolgsantwort

{ "ok": true, "data": { "id": "act_abc123", "name": "Token mit CRM-Daten anreichern v2", "trigger": "post_login", "status": "active", "code": "async function handler(context, api) { ... }", "order": 1, "timeout": 8000, "updatedAt": "2025-02-18T11:00:00Z" } }

Action löschen

DELETE/api/actions/[id]Requires: manage:actions

Eine Action dauerhaft löschen. Die Action wird sofort aus der Ausführungspipeline entfernt. Ausführungsprotokolle für diese Action werden aufbewahrt.

Erfolgsantwort

{ "ok": true, "data": { "deleted": true } }

Action-Status umschalten

PATCH/api/actions/[id]Requires: manage:actions

Eine Action zwischen active und inactive umschalten. Nur aktive Actions werden während Authentifizierungsflows ausgeführt.

Anforderungs-Body

{ "status": "active" }

Gültige Werte: active, inactive.

Erfolgsantwort

{ "ok": true, "data": { "id": "act_abc123", "status": "active", "updatedAt": "2025-02-18T11:30:00Z" } }

Ausführungsprotokolle

GET/api/actions/[id]/logsRequires: manage:actions

Ausführungsprotokolle für eine bestimmte Action abrufen. Jeder Protokolleintrag zeichnet auf, ob die Ausführung erfolgreich war oder fehlgeschlagen ist, die Dauer und etwaige Fehlermeldungen. Protokolle sind nach Zeitstempel absteigend geordnet.

Abfrageparameter

ParameterTypBeschreibung
pageintegerSeitennummer (Standard: 1)
limitintegerElemente pro Seite (Standard: 20)

Erfolgsantwort

{ "ok": true, "data": { "data": [ { "id": "log_abc123", "actionId": "act_abc123", "trigger": "post_login", "status": "success", "duration": 234, "userId": "usr_xyz789", "createdAt": "2025-02-18T09:50:00Z" }, { "id": "log_def456", "actionId": "act_abc123", "trigger": "post_login", "status": "error", "duration": 5001, "error": "Action nach 5000ms abgelaufen", "userId": "usr_abc123", "createdAt": "2025-02-18T09:48:00Z" }, { "id": "log_ghi789", "actionId": "act_abc123", "trigger": "post_login", "status": "error", "duration": 112, "error": "TypeError: Cannot read property 'email' of undefined", "userId": "usr_def456", "createdAt": "2025-02-18T09:45:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 14535, "totalPages": 727 } } }

Protokollstatus-Werte: success, error.

Triggertypen

Actions können an einen von sechs Triggerpunkten in der Authentifizierungspipeline gebunden werden:

TriggerWann ausgelöstAnwendungsfälle
pre_loginBevor die Keycloak-Authentifizierung versucht wirdLogin von bestimmten IPs oder E-Mail-Domains blockieren, benutzerdefiniertes Rate Limiting
post_loginNach erfolgreicher Authentifizierung, bevor Tokens ausgestellt werdenTokens mit externen Daten anreichern, benutzerdefinierte Analysen protokollieren, mit CRM synchronisieren
pre_signupBevor ein neues Benutzerkonto erstellt wirdWegwerf-E-Mails blockieren, benutzerdefinierte Validierung erzwingen, externe Sperrlisten prüfen
post_signupNachdem ein neues Benutzerkonto erstellt wurdeWillkommensbenachrichtigung senden, Datensätze in externen Systemen erstellen, Standardrollen zuweisen
post_change_passwordNachdem ein Benutzer sein Passwort geändert hatZwischengespeicherte Anmeldedaten ungültig machen, externe Systeme benachrichtigen, Audit-Protokoll
pre_m2m_tokenBevor ein M2M-Token ausgestellt wirdClient-Scopes validieren, benutzerdefinierte Claims hinzufügen, Zeitbeschränkungen erzwingen

Ausführungsreihenfolge

Wenn mehrere aktive Actions denselben Trigger teilen, werden sie sequenziell in aufsteigender Reihenfolge des order-Werts ausgeführt. Wenn eine Action fehlschlägt (einen Fehler auslöst oder abläuft), werden nachfolgende Actions für diesen Trigger weiterhin ausgeführt, es sei denn, die fehlschlagende Action verweigert die Anforderung explizit.

ActionContext-Objekt

Jede Action erhält ein context-Objekt als erstes Argument. Die Form variiert je nach Triggertyp.

pre_login / post_login

{ user: { id: "usr_abc123", email: "[email protected]", username: "alice", firstName: "Alice", lastName: "Müller", roles: ["editor", "viewer"], emailVerified: true, phoneNumber: "+4930123456789", phoneNumberVerified: true, metadata: {} }, connection: { method: "password", // "password" | "magic_link" | "social" | "sso" provider: null, // Name des Social-Providers (z.B. "google") oder null ipAddress: "203.0.113.50", userAgent: "Mozilla/5.0 ...", timestamp: "2025-02-18T10:00:00Z" }, tenant: "acme-gmbh" }

Bei pre_login kann das user-Objekt null sein, wenn der Benutzer noch nicht aufgelöst wurde (z.B. falsche E-Mail). connection.method und connection.ipAddress sind immer verfügbar.

pre_signup / post_signup

{ user: { email: "[email protected]", username: "neuerbenutzer", firstName: "Neuer", lastName: "Benutzer" }, connection: { method: "password", ipAddress: "203.0.113.50", userAgent: "Mozilla/5.0 ...", timestamp: "2025-02-18T10:00:00Z" }, tenant: "acme-gmbh" }

Bei post_signup enthält das user-Objekt auch id und roles.

post_change_password

{ user: { id: "usr_abc123", email: "[email protected]" }, tenant: "acme-gmbh" }

pre_m2m_token

{ application: { id: "app_xyz789", name: "Backend-Dienst", clientId: "m2m-client-id", type: "M2M" }, requestedScopes: ["read:users", "manage:roles"], tenant: "acme-gmbh" }

ActionResult (API-Objekt)

Das zweite Argument, das an Actions übergeben wird, ist das api-Objekt, das Methoden bereitstellt, um den Authentifizierungsflow zu beeinflussen:

MethodeVerfügbar inBeschreibung
api.setCustomClaim(key, value)post_login, pre_m2m_tokenEinen benutzerdefinierten Claim zum Zugriffs-Token hinzufügen
api.setMetadata(key, value)post_login, post_signupBenutzermetadaten setzen (in der Datenbank gespeichert)
api.deny(reason)pre_login, pre_signup, pre_m2m_tokenDen Authentifizierungsversuch mit einem Grund ablehnen
api.log(message)Alle TriggerEine Nachricht in das Ausführungsprotokoll der Action schreiben
api.fetch(url, options)Alle TriggerEine HTTP-Anforderung stellen (eingeschränktes fetch mit Timeout)

Beispiel: Registrierung für Wegwerf-E-Mails ablehnen

async function handler(context, api) { const disposableDomains = ['tempmail.com', 'throwaway.email', 'guerrillamail.com']; const domain = context.user.email.split('@')[1]; if (disposableDomains.includes(domain)) { api.deny('Wegwerf-E-Mail-Adressen sind nicht erlaubt'); return; } api.log('Registrierung erlaubt für Domain: ' + domain); }

Beispiel: Token nach Login anreichern

async function handler(context, api) { try { const response = await api.fetch('https://crm.example.com/api/lookup', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer crm-api-key' }, body: JSON.stringify({ email: context.user.email }) }); if (response.ok) { const data = await response.json(); api.setCustomClaim('crm_id', data.customerId); api.setCustomClaim('plan', data.subscriptionPlan); api.log('Token angereichert: plan=' + data.subscriptionPlan); } else { api.log('CRM-Abfrage fehlgeschlagen: ' + response.status); } } catch (error) { api.log('CRM-Abfragefehler: ' + error.message); // Login nicht verweigern, wenn die Anreicherung fehlschlägt } }

Beispiel: M2M-Token außerhalb der Geschäftszeiten blockieren

async function handler(context, api) { var hour = new Date().getUTCHours(); if (hour < 6 || hour > 22) { api.deny('M2M-Tokens können außerhalb der Geschäftszeiten nicht ausgestellt werden (06:00-22:00 UTC)'); return; } api.log('M2M-Token für ' + context.application.name + ' um UTC-Stunde ' + hour + ' ausgestellt'); }

Sandbox-Einschränkungen

Actions werden in einer Sandbox-Umgebung mit eingeschränktem Scope ausgeführt. Die folgenden Muster werden zur Code-Validierungszeit erkannt und blockiert (beim Erstellen und Aktualisieren). Code, der eines dieser Muster enthält, wird mit einem BLOCKED_PATTERN-Fehler abgelehnt:

  • require( — keine CommonJS-Modulimporte
  • import — keine ES-Modulimporte
  • process. — kein Zugriff auf das Node.js-Process-Objekt
  • child_process — keine Shell-Ausführung
  • fs. / fs/promises — kein Dateisystemzugriff
  • global. / globalThis. — kein Zugriff auf den globalen Scope
  • Dynamische Code-Auswertungsmuster — keine Laufzeit-Codegenerierung aus Zeichenketten

Die api.fetch()-Methode wird als sichere Alternative zu externen HTTP-Bibliotheken bereitgestellt. Sie unterstützt GET-, POST-, PUT-, PATCH- und DELETE-Methoden mit JSON- oder Text-Bodys. Das Timeout wird von der timeout-Einstellung der Action übernommen.

Laufzeitlimits

LimitWert
Maximale AusführungszeitPro Action konfigurierbar (Standard 5000ms, max 10000ms)
Maximale Code-Größe64 KB
Maximale api.fetch()-Antwortgröße1 MB
Verfügbare GlobalsJSON, Date, Math, String, Number, Array, Object, Map, Set, Promise, RegExp, console.log (umgeleitet zu api.log)

Fehlerbehandlung

Wenn eine Action einen unbehandelten Fehler auslöst oder abläuft:

  1. Der Fehler wird im Ausführungsprotokoll der Action protokolliert.
  2. Der errorCount der Action wird erhöht.
  3. Der Authentifizierungsflow wird fortgesetzt (Actions blockieren die Authentifizierung standardmäßig nicht, es sei denn, api.deny() wird aufgerufen).
  4. Wenn die Action kritisch ist, verwende api.deny() explizit in deinem Fehlerhandler.

Action-Fehler blockieren die Authentifizierung standardmäßig nicht. Wenn du eine fehlschlagende Action benötigst, um den Login zu verhindern (z.B. eine Compliance-Prüfung), musst du api.deny() explizit in deinem Catch-Block aufrufen. Andernfalls wird der Benutzer authentifiziert, auch wenn die Action fehlschlägt.

Blueprint Visual Editor

Die Auris-Konsole enthält einen visuellen Node-Editor (Blueprint-Editor) zum Erstellen von Actions über eine Drag-and-Drop-Oberfläche anstatt JavaScript zu schreiben. Der Blueprint-Editor generiert JSON-Regeldefinitionen, die zur Laufzeit in äquivalentes JavaScript kompiliert werden.

Der Blueprint-Editor ist eine Alternative zum Code-Editor — beide erzeugen dasselbe Ergebnis. Actions, die mit dem Blueprint-Editor erstellt wurden, können als Code angezeigt und bearbeitet werden, und umgekehrt.

Details zum Blueprint-Editor findest du in der Konsolendokumentation.


Zugehörige Referenzen