Diseño de Autenticación Consciente del Tenant con API Gateway y Lambda

Las aplicaciones multi-tenant deben autenticar al usuario y, además, determinar a qué tenant —cliente, cuenta u organización— pertenece. Ese contexto de tenant debe seguir siendo confiable a medida que la solicitud atraviesa API Gateway, las funciones Lambda y la capa de datos.

Este artículo presenta un patrón práctico para transportar la identidad del tenant a través de una API serverless en AWS sin confiar en identificadores de tenant provistos por el cliente.

Arquitectura de autenticación multi-tenant

La autenticación es solo la primera verificación

La autenticación responde: ¿Quién está haciendo esta solicitud?

Una aplicación multi-tenant también debe responder:

  • ¿A qué tenant pertenece este usuario?
  • ¿El usuario está activo dentro de ese tenant?
  • ¿Qué operaciones puede realizar el usuario?
  • ¿A qué datos de qué tenant puede acceder la solicitud?

El identificador del tenant debe provenir de un token de identidad confiable, no de un query parameter, un header de la solicitud, o una URL provista por el cliente.

Una implementación común usa un JSON Web Token, o JWT. Un JWT es un token firmado que contiene claims como el identificador del usuario, el emisor del token, el tiempo de expiración, los roles y el identificador del tenant.

Un token puede contener claims similares a estos:

{
  "sub": "user-789",
  "tenantId": "clinic-123",
  "roles": ["scheduler"],
  "scope": "appointments:read appointments:write"
}

El token demuestra que el proveedor de identidad emitió esos claims. No garantiza automáticamente que cada función Lambda los use correctamente.

Un patrón práctico de autenticación

1. Emite el identificador del tenant como un claim confiable

Usa Amazon Cognito, un proveedor de identidad externo, o un servicio de autenticación propio para emitir el JWT.

Incluye un identificador de tenant estable, como tenantId. Mantén los claims pequeños y limitados a la información necesaria para autorizar la solicitud. Evita colocar documentos de permisos extensos, configuración del cliente, o atributos que cambian con frecuencia dentro del token.

2. Valida el token en API Gateway

Configura un autorizador JWT de API Gateway cuando el proveedor de identidad admita validación estándar de JWT.

API Gateway puede validar propiedades importantes del token, incluyendo:

  • La firma digital
  • El emisor del token
  • La audiencia prevista
  • El tiempo de expiración
  • Los scopes requeridos

Las solicitudes con tokens inválidos o expirados deben rechazarse antes de que se ejecute la función Lambda del backend.

Un Lambda authorizer puede ser más apropiado cuando la autorización requiere lógica personalizada, tokens heredados, múltiples proveedores de identidad, o una verificación inmediata del estado del tenant.

3. Propaga el contexto de identidad verificado hacia adelante

Después de la validación, API Gateway expone los claims verificados a través del contexto de la solicitud. La función Lambda del backend debe leer tenantId, sub, roles y scopes desde ese contexto.

No debe aceptar un identificador de tenant alternativo proveniente del cliente.

const claims = event.requestContext.authorizer.jwt.claims;

const tenantId = claims.tenantId;
const userId = claims.sub;

if (!tenantId || !userId) {
  return {
    statusCode: 403,
    body: JSON.stringify({ message: "Missing tenant context" }),
  };
}

Centraliza esta extracción y validación en una función compartida, de modo que todos los endpoints apliquen las mismas reglas.

4. Aplica la autorización dentro de la función Lambda

La validación del token demuestra que los claims son auténticos. El backend todavía debe decidir si la operación está permitida.

Por ejemplo, un usuario con appointments:read puede consultar citas, pero no debería poder modificarlas. Un administrador de tenant puede gestionar personal, pero no debería acceder a operaciones administrativas a nivel de plataforma.

Realiza verificaciones generales usando scopes o roles del token. Realiza verificaciones específicas por recurso en la aplicación cuando la autorización dependa de los datos actuales, la propiedad del recurso, el estado de la suscripción, o reglas de negocio.

5. Delimita cada operación de datos por tenant

El aislamiento de tenants debe continuar hasta la base de datos.

Para DynamoDB, incluye el identificador del tenant en la partition key o en el patrón de acceso principal:

PK = TENANT#clinic-123
SK = APPOINTMENT#2026-08-04#appointment-456

Para Aurora u otra base de datos relacional, incluye tenant_id en las consultas e índices:

SELECT *
FROM appointments
WHERE tenant_id = :tenantId
  AND appointment_id = :appointmentId;

No obtengas un registro por su identificador global y verifiques el tenant después. Haz que la condición del tenant sea parte de la propia operación de base de datos.

Flujo de trabajo de una solicitud de autenticación de tenant

Ejemplo: SaaS de agendamiento de citas

Considera una plataforma de agendamiento que da servicio a clínicas médicas independientes.

Un usuario inicia sesión a través de Cognito y recibe un token que contiene:

{
  "sub": "user-789",
  "tenantId": "clinic-123",
  "scope": "appointments:read"
}

El usuario llama a:

GET /appointments
Authorization: Bearer eyJ...

API Gateway valida el token y pasa sus claims a la función Lambda de citas. La función extrae clinic-123 de los claims verificados y consulta únicamente los registros cuya partition key comienza con TENANT#clinic-123.

Incluso si el cliente envía este header:

X-Tenant-Id: clinic-999

la aplicación lo ignora. La identidad del tenant proviene exclusivamente del contexto del token validado.

Lista de verificación de implementación

  1. Agrega un identificador de tenant estable al registro de identidad confiable del usuario.
  2. Incluye ese identificador como un claim firmado del token.
  3. Valida emisor, audiencia, firma, expiración y scopes del token.
  4. Rechaza solicitudes sin identificadores verificados de usuario y tenant.
  5. Lee el contexto del tenant desde API Gateway, nunca desde la entrada del cliente.
  6. Aplica autorización por rol, por scope y por recurso de forma separada.
  7. Incluye el identificador del tenant en cada patrón de acceso a base de datos.
  8. Registra tenantId, userId, ID de solicitud, ruta y resultado de la autorización.
  9. Prueba intentos de acceder a identificadores de otro tenant.
  10. Devuelve errores de autorización genéricos sin exponer detalles del tenant.

Compensaciones y errores comunes

Autorizador JWT versus Lambda authorizer

Un autorizador JWT es más simple y evita ejecutar código de autorización personalizado en cada solicitud. Su limitación es que valida los claims del token, pero no verifica automáticamente si un tenant fue suspendido momentos después de emitido el token.

Un Lambda authorizer puede realizar verificaciones adicionales, pero agrega costo de ejecución, latencia, código y otro punto de falla. El cacheo del autorizador reduce el trabajo repetido, pero puede retrasar la aplicación de cambios de permisos o de estado del tenant.

Tratar el claim del tenant como autorización completa

Un tenantId válido solo establece el contexto del tenant. No demuestra que el usuario pueda realizar todas las operaciones dentro de ese tenant.

Mantén la autenticación, la resolución del tenant, las verificaciones de permisos y el aislamiento de datos como controles distintos.

Permitir acceso a datos sin alcance definido

El error de implementación más peligroso es una función de repositorio o consulta que solo acepta un identificador de registro:

getAppointment(appointmentId);

Prefiere interfaces que requieran el contexto del tenant:

getAppointment(tenantId, appointmentId);

Esto hace que sea más difícil introducir accesos inseguros durante el desarrollo cotidiano.

Conclusión

Un diseño confiable de autenticación multi-tenant transporta un identificador de tenant verificado desde el proveedor de identidad, a través de API Gateway, hasta cada operación de Lambda y de base de datos. API Gateway debe rechazar identidades inválidas de forma temprana, mientras que las funciones del backend siguen siendo responsables de la autorización y del acceso a datos con alcance por tenant.

Como siguiente paso, revisa una ruta crítica de API desde la validación del token hasta la consulta de base de datos, e identifica cada punto donde el contexto del tenant podría faltar, ser reemplazado, o ser ignorado.