Actions & Exécution en Sandbox
Les systèmes d’authentification ont des comportements communs à tous — vérification des credentials, émission des tokens, gestion des sessions. Mais chaque application a des exigences personnalisées : bloquer certains fournisseurs d’email, enrichir les tokens avec des données d’un système RH, appliquer des restrictions géographiques.
Sans un mécanisme d’extension, les utilisateurs devraient forker Auris ou implémenter des contournements complexes. Les Actions permettent d’injecter du code JavaScript personnalisé dans des points précis du flux d’authentification — dans un sandbox sécurisé qui prévient l’accès aux ressources non autorisées.
Le Modèle Sandbox
Auris exécute les actions dans un contexte JavaScript isolé construit avec le constructeur Function de Node.js. Le scope du sandbox est délibérément minimal :
Toujours disponible :
context: L’objetActionContext(voir ci-dessous)fetch: Requêtes HTTP vers des APIs externes (viacontext.fetch)console: Logging limité (log,warn,error)
Toujours bloqué :
// Ces patterns sont refusés statiquement avant l'exécution :
require(...)
import ...
process.env
global.something
child_process
fs.readFileL’analyse statique des patterns bloqués se produit à la compilation de l’action (quand tu la sauvegardes dans la Console), pas au runtime. Cela signifie que les actions invalides sont rejetées immédiatement, pas à la prochaine connexion de l’utilisateur.
L’Interface ActionContext
Chaque action reçoit un objet context avec les informations sur l’événement actuel :
interface ActionContext {
user: {
id: string
email: string
username: string
roles: string[]
metadata: Record<string, unknown>
}
request: {
ip: string
userAgent: string
geoip: {
country: string
city: string
latitude: number
longitude: number
}
}
tenant: {
id: string
name: string
}
application: {
id: string
clientId: string
name: string
}
trigger: string // ex: "pre_login", "post_login"
fetch: typeof globalThis.fetch // Fetch API standard
console: {
log: (...args: unknown[]) => void
warn: (...args: unknown[]) => void
error: (...args: unknown[]) => void
}
}L’Interface ActionResult
Les actions retournent (ou peuvent retourner) un objet ActionResult :
interface ActionResult {
allow?: boolean // false bloque l'opération
claims?: Record<string, unknown> // Claims ajoutés au token JWT
metadata?: Record<string, unknown> // Metadata persistée sur l'utilisateur
reason?: string // Raison du blocage (affichée à l'utilisateur)
}Chaque propriété est optionnelle. Une action qui retourne {} ou undefined est une no-op.
Les Six Triggers
Les actions sont assignées à des triggers spécifiques dans le flux d’authentification :
| Trigger | Quand | Peut Bloquer | Peut Enrichir |
|---|---|---|---|
pre_login | Avant la vérification des credentials | ✅ | ❌ |
post_login | Après authentification réussie | ❌ | ✅ (claims, metadata) |
pre_signup | Avant la création du compte | ✅ | ❌ |
post_signup | Après la création du compte | ❌ | ✅ (metadata) |
post_change_password | Après changement de mot de passe | ❌ | ❌ |
pre_m2m_token | Avant l’émission de tokens M2M | ✅ | ✅ (claims) |
Fail-secure : Si une action lève une exception non gérée, l’opération est bloquée (pour les triggers pre_*) ou la modification est ignorée (pour les triggers post_*). Utilise try-catch dans tes actions si tu veux un comportement de dégradation gracieuse.
Exécution Séquentielle
Quand plusieurs actions sont assignées au même trigger, elles sont exécutées séquentiellement dans l’ordre défini dans la Console. Si une action bloque l’opération (allow: false), les actions suivantes ne sont pas exécutées.
Modèle de Sécurité
| Capacité | Actions PEUVENT | Actions NE PEUVENT PAS |
|---|---|---|
| Lire les données utilisateur | ✅ context.user.* | ❌ Accéder à d’autres utilisateurs |
| Faire des requêtes HTTP | ✅ context.fetch | ❌ require('node-fetch') |
| Logger | ✅ context.console.* | ❌ Écrire sur le système de fichiers |
| Modifier les claims JWT | ✅ Retourner claims | ❌ Modifier les claims existants |
| Accéder aux variables d’environnement | ❌ | ❌ |
| Spawner des processus | ❌ | ❌ |
Caractéristiques de Performance
| Opération | Temps Typique |
|---|---|
| Analyse statique des patterns bloqués | < 0.1 ms |
| Construction du contexte sandbox | ~0.5 ms |
| Logique simple (pas de réseau) | 1–5 ms |
| Avec appel API HTTP externe | 50–500 ms |
| Timeout d’exécution max | 5 000 ms |
Les actions qui dépassent 5 000 ms sont interrompues de force et traitées comme une exception.
L’Éditeur Blueprint
En plus de l’éditeur de code JavaScript, la Console Auris fournit un Blueprint Editor — un éditeur de flux visuel node-based pour les utilisateurs qui préfèrent une interface no-code/low-code.
Le Blueprint Editor et l’éditeur de code sont bidirectionnels : les modifications dans l’un se reflètent dans l’autre en temps réel. Les types de nœuds disponibles :
- Trigger : Point d’entrée du flux
- Condition : Branchement basé sur des valeurs context (si/sinon)
- Logic Gate : ET, OU, NON
- Deny Action : Bloquer l’opération avec un message
- Set Claims : Ajouter/modifier des claims JWT
- Set Metadata : Persister des données sur le profil utilisateur
- Log : Logger un message avec niveau de sévérité
Exemples
Bloquer les Emails Jetables (pre_signup)
// Trigger: pre_signup
const BLOCKED_DOMAINS = ['mailinator.com', 'guerrillamail.com', 'tempmail.com', 'throwaway.email']
const domain = context.user.email.split('@')[1]?.toLowerCase()
if (BLOCKED_DOMAINS.includes(domain)) {
return {
allow: false,
reason: 'Les adresses email temporaires ou jetables ne sont pas acceptées.',
}
}Enrichir le Token avec des Données RH (post_login)
// Trigger: post_login
try {
const hrRes = await context.fetch(`https://hr.internal/api/employees/${context.user.id}`, {
headers: { Authorization: `Bearer ${HR_API_TOKEN}` },
})
if (hrRes.ok) {
const employee = await hrRes.json()
return {
claims: {
department: employee.department,
cost_center: employee.costCenter,
manager_id: employee.managerId,
},
}
}
} catch (err) {
context.console.warn('HR API indisponible, pas d\'enrichissement:', err.message)
}
// Retourne undefined → pas de modification des claimsRestriction Géographique (pre_login)
// Trigger: pre_login
const ALLOWED_COUNTRIES = ['IT', 'DE', 'FR', 'ES', 'NL', 'BE', 'PT']
const country = context.request.geoip?.country
if (country && !ALLOWED_COUNTRIES.includes(country)) {
return {
allow: false,
reason: `Connexions depuis ${country} non autorisées pour cette application.`,
}
}Concepts Associés
- OAuth 2.0 & OIDC — Le flux d’authentification où les actions s’insèrent
- Tokens — Comment les claims retournés par les actions se retrouvent dans les JWTs
- MFA Adaptatif — Combiner les actions avec le risk scoring pour des politiques avancées
- Multi-Tenancy — Les actions peuvent être scoped par tenant avec
context.tenant