Skip to Content

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’objet ActionContext (voir ci-dessous)
  • fetch : Requêtes HTTP vers des APIs externes (via context.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.readFile

L’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 :

TriggerQuandPeut BloquerPeut Enrichir
pre_loginAvant la vérification des credentials✅❌
post_loginAprès authentification réussie❌✅ (claims, metadata)
pre_signupAvant la création du compte✅❌
post_signupAprès la création du compte❌✅ (metadata)
post_change_passwordAprès changement de mot de passe❌❌
pre_m2m_tokenAvant 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 PEUVENTActions 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érationTemps 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 externe50–500 ms
Timeout d’exécution max5 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 claims

Restriction 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