Skip to Content

Actions y ejecución en sandbox

El problema: extensibilidad sin bifurcar

Cada plataforma de identidad eventualmente se enfrenta a la misma tensión: los clientes necesitan lógica personalizada en sus flujos de autenticación, pero la plataforma no puede anticipar cada requisito. Sin un mecanismo de extensibilidad, las opciones son limitadas.

Lo que los clientes realmente necesitan es la capacidad de ejecutar código personalizado en puntos específicos del flujo de autenticación — antes del inicio de sesión (para bloquear intentos sospechosos), después del inicio de sesión (para enriquecer tokens con claims personalizados), después del registro (para activar flujos de onboarding), y más.

El desafío es hacerlo de forma segura. El código del cliente se ejecuta dentro del servidor de autorización, que es el componente más crítico para la seguridad de toda la infraestructura.

Cómo funciona el sandbox de Auris

Las Actions de Auris ejecutan JavaScript personalizado dentro de un entorno controlado usando el constructor Function de JavaScript. Este mecanismo crea una función a partir de una cadena de código con un scope explícito — el código de la action solo ve las variables que Auris proporciona explícitamente.

Paso 1: Análisis estático

Antes de ejecutar cualquier código, Auris escanea el código fuente de la action buscando patrones bloqueados:

const BLOCKED_PATTERNS = [ 'require', // Sin carga de módulos 'import', // Sin importaciones de módulos ES 'process', // Sin acceso a process.env, process.exit, etc. 'global', // Sin acceso al objeto global 'child_process', // Sin creación de subprocesos 'fs', // Sin acceso al sistema de ficheros ]

Paso 2: Construcción de la función

El código de la action se usa para construir una función con context como único parámetro:

const fn = new Function('context', actionCode) fn(contextObject)

El contextObject contiene solo lo que Auris decide exponer:

const context = { user: { id, email, roles, metadata }, tenant: { id, plan }, event: { type, timestamp, ipAddress }, // No hay: fetch, XMLHttpRequest, process, global, require, etc. }

Paso 3: Ejecución con timeout

La función se ejecuta con un timeout de 50ms. Si la action no retorna dentro del límite de tiempo, se cancela y se usa el comportamiento predeterminado (permitir).

Tipos de Actions disponibles

TipoCuándo se ejecutaPuede bloquear
post-loginDespués de la autenticación exitosa, antes de emitir tokensSí
post-registerDespués del registro de un nuevo usuarioNo
pre-token-issueInmediatamente antes de emitir tokensSí
post-logoutDespués de que el usuario cierra sesiónNo

La API del contexto

context.user

{ id: string // ID del usuario (usr_xxx) email: string // Dirección de email emailVerified: boolean // Si el email ha sido verificado roles: string[] // Roles asignados metadata: Record<string, unknown> // Metadatos personalizados del usuario }

context.event

{ type: 'login' | 'register' | 'token-issue' | 'logout' timestamp: string // ISO 8601 ipAddress: string // IP del solicitante userAgent: string // User agent del navegador/cliente riskScore: number // Puntuación de riesgo calculada (0-100) }

context.access — enriquecer tokens

// Añadir claims personalizados al access token context.access.setCustomClaim('department', 'engineering') context.access.setCustomClaim('subscription_tier', 'pro')

context.deny — bloquear autenticación

// Bloquear el inicio de sesión con un mensaje context.deny('Acceso bloqueado: tu cuenta ha sido suspendida.')

Ejemplo: enriquecimiento de tokens

// Action: añadir departamento del usuario al token async function handler(context) { const dept = context.user.metadata.department if (dept) { context.access.setCustomClaim('department', dept) } // No llamar a context.deny() = permitir }

Ejemplo: control de acceso basado en reglas

// Action: bloquear inicio de sesión desde países de alto riesgo async function handler(context) { const allowedCountries = ['IT', 'DE', 'FR', 'US', 'GB'] const country = context.event.geo?.countryCode if (country && !allowedCountries.includes(country)) { context.deny(`Inicio de sesión desde ${country} no está permitido.`) } }

El análisis estático no es por sí mismo un límite de seguridad. Un atacante determinado podría ofuscar palabras clave bloqueadas. El análisis estático existe para detectar el mal uso accidental y proporcionar mensajes de error claros. La seguridad real proviene del objeto de scope restringido proporcionado a la función construida.