Skip to Content

API Actions Engine

Le Actions sono snippet di codice JavaScript personalizzato che si eseguono in punti specifici durante i flussi di autenticazione. Consentono di estendere Auris con logica personalizzata senza modificare la piattaforma core: arricchire i token con dati esterni, bloccare registrazioni sospette, applicare policy di password personalizzate o sincronizzare i dati utente con sistemi esterni.

Le Actions vengono eseguite in un ambiente sandboxed con scope limitato. Ogni action è associata a un punto di trigger (es. post_login) e viene eseguita in ordine di priorità. Più action possono essere collegate allo stesso trigger.

Tutti gli endpoint delle actions richiedono l’header x-tenant. La creazione e gestione delle actions richiede accesso a livello admin (implicato dal permesso admin:all o dal permesso manage:actions).

Ciclo di Vita di un’Action

  1. Crea un’action con un tipo di trigger e codice JavaScript.
  2. Testa l’action esaminando i log di esecuzione.
  3. Imposta lo stato dell’action su active per abilitarla in produzione.
  4. Monitora l’esecuzione tramite l’endpoint dei log.

CRUD Actions

Elenco Actions

GET/api/actionsRequires: manage:actions

Elenca tutte le actions per il tenant. Restituisce i metadati dell’action incluso il tipo di trigger, lo stato, le statistiche di esecuzione e l’ordine. Le actions vengono eseguite in ordine ascendente del campo order per ogni tipo di trigger.

Parametri di query

ParametroTipoDescrizione
pageintegerNumero di pagina (default: 1)
limitintegerElementi per pagina (default: 20)
triggerstringFiltra per tipo di trigger (es. post_login)
statusactive | inactiveFiltra per stato

Risposta di successo

{ "ok": true, "data": { "data": [ { "id": "act_abc123", "name": "Arricchisci Token con Dati CRM", "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" } ], "pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 } } }

Crea Action

POST/api/actionsRequires: manage:actions

Crea una nuova action. L’action viene creata con stato inactive di default. Impostala su active tramite l’endpoint di toggle dopo i test. Il codice JavaScript viene validato per i pattern bloccati prima della memorizzazione.

Corpo della richiesta

{ "name": "Arricchisci Token con Dati CRM", "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 }
CampoTipoObbligatorioDescrizione
namestringSìNome leggibile dall’utente
triggerstringSìPunto di trigger (vedi Tipi di Trigger)
codestringSìCorpo della funzione JavaScript
orderintegerNoOrdine di esecuzione nel trigger (default: 0, più basso = primo)
timeoutintegerNoTempo massimo di esecuzione in millisecondi (default: 5000, max: 10000)

Risposta di successo

{ "ok": true, "data": { "id": "act_ghi789", "name": "Arricchisci Token con Dati CRM", "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" } }

Codici di errore

CodiceHTTPDescrizione
VALIDATION_ERROR400Campi obbligatori mancanti o tipo di trigger non valido
BLOCKED_PATTERN400Il codice contiene un pattern bloccato (vedi Restrizioni Sandbox)
CODE_TOO_LARGE400Il codice supera la dimensione massima consentita

Ottieni Action

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

Recupera una singola action tramite ID, incluso il codice completo e le statistiche di esecuzione.

Aggiorna Action

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

Aggiorna il nome, il codice, il trigger, l’ordine o il timeout di un’action. Tutti i campi sono opzionali — vengono aggiornati solo i campi forniti. Il codice aggiornato viene ri-validato per i pattern bloccati.

Corpo della richiesta

{ "name": "Arricchisci Token con Dati CRM v2", "code": "async function handler(context, api) {\n // Logica aggiornata\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 }

Elimina Action

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

Elimina un’action definitivamente. L’action viene immediatamente rimossa dalla pipeline di esecuzione. I log di esecuzione per questa action vengono conservati.

Risposta di successo

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

Attiva/Disattiva Action

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

Alterna un’action tra lo stato active e inactive. Solo le action attive vengono eseguite durante i flussi di autenticazione.

Corpo della richiesta

{ "status": "active" }

Valori validi: active, inactive.

Risposta di successo

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

Log di Esecuzione

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

Recupera i log di esecuzione per un’action specifica. Ogni voce di log registra se l’esecuzione ha avuto successo o è fallita, la durata e i messaggi di errore. I log sono ordinati per timestamp in ordine decrescente.

Parametri di query

ParametroTipoDescrizione
pageintegerNumero di pagina (default: 1)
limitintegerElementi per pagina (default: 20)

Risposta di successo

{ "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 scaduta dopo 5000ms", "userId": "usr_abc123", "createdAt": "2025-02-18T09:48:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 14535, "totalPages": 727 } } }

Valori di stato del log: success, error.

Tipi di Trigger

Le Actions possono essere collegate a uno dei sei punti di trigger nella pipeline di autenticazione:

TriggerSi attiva quandoCasi d’uso
pre_loginPrima che venga tentata l’autenticazione KeycloakBlocca il login da IP o domini email specifici, rate limiting personalizzato
post_loginDopo l’autenticazione riuscita, prima dell’emissione dei tokenArricchisci i token con dati esterni, log analytics personalizzati, sincronizza con CRM
pre_signupPrima della creazione di un nuovo account utenteBlocca email usa e getta, applica validazione personalizzata, controlla blocklist esterne
post_signupDopo la creazione di un nuovo account utenteInvia notifica di benvenuto, crea record in sistemi esterni, assegna ruoli predefiniti
post_change_passwordDopo che un utente cambia la propria passwordInvalida credenziali in cache, notifica sistemi esterni, log di audit
pre_m2m_tokenPrima dell’emissione di un token M2MValida scope client, aggiungi claim personalizzati, applica restrizioni orarie

Ordine di Esecuzione

Quando più action attive condividono lo stesso trigger, vengono eseguite in sequenza in ordine ascendente del valore order. Se un’action fallisce (lancia un errore o va in timeout), le action successive per quel trigger vengono comunque eseguite, a meno che l’action fallita non neghi esplicitamente la richiesta.

Oggetto ActionContext

Ogni action riceve un oggetto context come primo argomento. La forma varia per tipo di trigger.

pre_login / post_login

{ user: { id: "usr_abc123", email: "[email protected]", username: "alice", firstName: "Alice", lastName: "Rossi", roles: ["editor", "viewer"], emailVerified: true, phoneNumber: "+39021234567", phoneNumberVerified: true, metadata: {} }, connection: { method: "password", // "password" | "magic_link" | "social" | "sso" provider: null, // nome del social provider (es. "google") o null ipAddress: "203.0.113.50", userAgent: "Mozilla/5.0 ...", timestamp: "2025-02-18T10:00:00Z" }, tenant: "acme-corp" }

Per pre_login, l’oggetto user può essere null se l’utente non è ancora stato risolto (es. email errata). connection.method e connection.ipAddress sono sempre disponibili.

pre_signup / post_signup

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

Per post_signup, l’oggetto user include anche id e roles.

post_change_password

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

pre_m2m_token

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

Oggetto ActionResult (API)

Il secondo argomento passato alle actions è l’oggetto api, che fornisce metodi per influenzare il flusso di autenticazione:

MetodoDisponibile inDescrizione
api.setCustomClaim(key, value)post_login, pre_m2m_tokenAggiunge un claim personalizzato all’access token
api.setMetadata(key, value)post_login, post_signupImposta metadati utente (persistiti nel database)
api.deny(reason)pre_login, pre_signup, pre_m2m_tokenNega il tentativo di autenticazione con un motivo
api.log(message)Tutti i triggerScrive un messaggio nel log di esecuzione dell’action
api.fetch(url, options)Tutti i triggerEffettua una richiesta HTTP (fetch con timeout limitato)

Esempio: Nega Registrazione per Email Usa e Getta

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('Gli indirizzi email usa e getta non sono consentiti'); return; } api.log('Registrazione consentita per il dominio: ' + domain); }

Esempio: Arricchisci Token Dopo il Login

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 arricchito: plan=' + data.subscriptionPlan); } else { api.log('Ricerca CRM fallita: ' + response.status); } } catch (error) { api.log('Errore ricerca CRM: ' + error.message); // Non negare il login se l'arricchimento fallisce } }

Esempio: Blocca Token M2M Fuori dall’Orario Lavorativo

async function handler(context, api) { var hour = new Date().getUTCHours(); if (hour < 6 || hour > 22) { api.deny('I token M2M non possono essere emessi fuori dall\'orario lavorativo (06:00-22:00 UTC)'); return; } api.log('Token M2M emesso per ' + context.application.name + ' all\'ora UTC ' + hour); }

Restrizioni Sandbox

Le Actions vengono eseguite in un ambiente sandboxed con scope limitato. I seguenti pattern vengono rilevati e bloccati al momento della validazione del codice (durante la creazione e l’aggiornamento). Il codice contenente uno di questi pattern viene rifiutato con un errore BLOCKED_PATTERN:

  • require( — nessun import di moduli CommonJS
  • import — nessun import di moduli ES
  • process. — nessun accesso all’oggetto process di Node.js
  • child_process — nessuna esecuzione di shell
  • fs. / fs/promises — nessun accesso al filesystem
  • global. / globalThis. — nessun accesso allo scope globale
  • Pattern di valutazione dinamica del codice — nessuna generazione di codice a runtime da stringhe

Il metodo api.fetch() è fornito come alternativa sicura alle librerie HTTP esterne. Supporta i metodi GET, POST, PUT, PATCH e DELETE con body JSON o testo. Il timeout viene ereditato dall’impostazione timeout dell’action.

Limiti di Runtime

LimiteValore
Tempo massimo di esecuzioneConfigurabile per action (default 5000ms, max 10000ms)
Dimensione massima del codice64 KB
Dimensione massima risposta api.fetch()1 MB
Globali disponibiliJSON, Date, Math, String, Number, Array, Object, Map, Set, Promise, RegExp, console.log (reindirizzato a api.log)

Gestione degli Errori

Quando un’action lancia un errore non gestito o va in timeout:

  1. L’errore viene registrato nel log di esecuzione dell’action.
  2. L’errorCount sull’action viene incrementato.
  3. Il flusso di autenticazione continua (le action non bloccano l’auth di default a meno che non venga chiamato api.deny()).
  4. Se l’action è critica, usa api.deny() esplicitamente nel tuo gestore degli errori.

Gli errori delle action non bloccano l’autenticazione di default. Se hai bisogno che un’action fallita impedisca il login (es. un controllo di conformità), devi chiamare api.deny() esplicitamente nel tuo blocco catch. Altrimenti, l’utente verrà autenticato anche se l’action fallisce.

Blueprint Visual Editor

La Console Auris include un editor visuale a nodi (Blueprint Editor) per creare action tramite un’interfaccia drag-and-drop invece di scrivere JavaScript. Il Blueprint Editor genera definizioni di regole JSON che vengono compilate in JavaScript equivalente a runtime.

Il Blueprint Editor è un’alternativa all’editor di codice — entrambi producono lo stesso risultato. Le action create con il Blueprint Editor possono essere visualizzate e modificate come codice e viceversa.

Consulta la documentazione della Console per i dettagli sul Blueprint Editor.


Pagine Correlate