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
- Eine Action mit einem Triggertyp und JavaScript-Code erstellen.
- Die Action durch Überprüfung der Ausführungsprotokolle testen.
- Den Status der Action auf
activesetzen, um sie in der Produktion zu aktivieren. - Ausführung über den Protokollendpunkt überwachen.
Action-CRUD
Actions auflisten
/api/actionsRequires: manage:actionsAlle 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
| Parameter | Typ | Beschreibung |
|---|---|---|
page | integer | Seitennummer (Standard: 1) |
limit | integer | Elemente pro Seite (Standard: 20) |
trigger | string | Nach Triggertyp filtern (z.B. post_login) |
status | active | inactive | Nach 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
/api/actionsRequires: manage:actionsEine 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
}| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
name | string | Ja | Menschenlesbarer Name |
trigger | string | Ja | Triggerpunkt (siehe Triggertypen) |
code | string | Ja | JavaScript-Funktionskörper |
order | integer | Nein | Ausführungsreihenfolge innerhalb des Triggers (Standard: 0, kleiner = zuerst) |
timeout | integer | Nein | Maximale 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
| Code | HTTP | Beschreibung |
|---|---|---|
VALIDATION_ERROR | 400 | Fehlende Pflichtfelder oder ungültiger Triggertyp |
BLOCKED_PATTERN | 400 | Code enthält ein blockiertes Muster (siehe Sandbox-Einschränkungen) |
CODE_TOO_LARGE | 400 | Code überschreitet die maximal zulässige Größe |
Action abrufen
/api/actions/[id]Requires: manage:actionsEine 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
/api/actions/[id]Requires: manage:actionsDen 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
/api/actions/[id]Requires: manage:actionsEine 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
/api/actions/[id]Requires: manage:actionsEine 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
/api/actions/[id]/logsRequires: manage:actionsAusfü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
| Parameter | Typ | Beschreibung |
|---|---|---|
page | integer | Seitennummer (Standard: 1) |
limit | integer | Elemente 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:
| Trigger | Wann ausgelöst | Anwendungsfälle |
|---|---|---|
pre_login | Bevor die Keycloak-Authentifizierung versucht wird | Login von bestimmten IPs oder E-Mail-Domains blockieren, benutzerdefiniertes Rate Limiting |
post_login | Nach erfolgreicher Authentifizierung, bevor Tokens ausgestellt werden | Tokens mit externen Daten anreichern, benutzerdefinierte Analysen protokollieren, mit CRM synchronisieren |
pre_signup | Bevor ein neues Benutzerkonto erstellt wird | Wegwerf-E-Mails blockieren, benutzerdefinierte Validierung erzwingen, externe Sperrlisten prüfen |
post_signup | Nachdem ein neues Benutzerkonto erstellt wurde | Willkommensbenachrichtigung senden, Datensätze in externen Systemen erstellen, Standardrollen zuweisen |
post_change_password | Nachdem ein Benutzer sein Passwort geändert hat | Zwischengespeicherte Anmeldedaten ungültig machen, externe Systeme benachrichtigen, Audit-Protokoll |
pre_m2m_token | Bevor ein M2M-Token ausgestellt wird | Client-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:
| Methode | Verfügbar in | Beschreibung |
|---|---|---|
api.setCustomClaim(key, value) | post_login, pre_m2m_token | Einen benutzerdefinierten Claim zum Zugriffs-Token hinzufügen |
api.setMetadata(key, value) | post_login, post_signup | Benutzermetadaten setzen (in der Datenbank gespeichert) |
api.deny(reason) | pre_login, pre_signup, pre_m2m_token | Den Authentifizierungsversuch mit einem Grund ablehnen |
api.log(message) | Alle Trigger | Eine Nachricht in das Ausführungsprotokoll der Action schreiben |
api.fetch(url, options) | Alle Trigger | Eine 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-Modulimporteimport— keine ES-Modulimporteprocess.— kein Zugriff auf das Node.js-Process-Objektchild_process— keine Shell-Ausführungfs./fs/promises— kein Dateisystemzugriffglobal./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
| Limit | Wert |
|---|---|
| Maximale Ausführungszeit | Pro Action konfigurierbar (Standard 5000ms, max 10000ms) |
| Maximale Code-Größe | 64 KB |
Maximale api.fetch()-Antwortgröße | 1 MB |
| Verfügbare Globals | JSON, 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:
- Der Fehler wird im Ausführungsprotokoll der Action protokolliert.
- Der
errorCountder Action wird erhöht. - Der Authentifizierungsflow wird fortgesetzt (Actions blockieren die Authentifizierung standardmäßig nicht, es sei denn,
api.deny()wird aufgerufen). - 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
- Actions & Sandbox-Ausführung — Wie die Sandbox-Ausführungsengine funktioniert
- Benutzerdefinierte Actions schreiben — Schritt-für-Schritt-Anleitung zur Erstellung von Actions
- Actions-Engine — Actions über die Konsole erstellen und verwalten
- Webhooks-API — Externe Ereigniszustellung, die Actions ergänzt