Autenticación Multi-Tenant con Amazon Cognito
La autenticación es solo una parte del problema en una aplicación SaaS multi-tenant. Después de identificar al usuario, cada solicitud de API también debe vincularse al tenant correcto y estar autorizada para las acciones que ese usuario puede realizar.
Amazon Cognito puede encargarse del inicio de sesión y de la emisión de tokens, pero el aislamiento de tenants todavía debe diseñarse explícitamente. El patrón que se describe a continuación mantiene la autenticación en Cognito, a la vez que aplica los límites entre tenants en las capas de aplicación y de datos.

Qué debe hacer Cognito
Un User Pool de Cognito administra a los usuarios y los autentica. Después de un inicio de sesión exitoso, Cognito emite JSON Web Tokens (JWTs), que son tokens firmados que contienen claims sobre la identidad autenticada.
Para una aplicación multi-tenant, la pregunta importante es: ¿a qué tenant pertenece esta identidad?
Un modelo práctico es mantener un identificador de tenant como:
tenant_123
El registro del usuario puede almacenar ese identificador como un atributo personalizado de Cognito, como custom:tenant_id. Si la API necesita el identificador del tenant en el access token, usa un mecanismo de personalización de tokens compatible con Cognito, como un Pre Token Generation Lambda trigger [SOURCE NEEDED].
La API debe derivar el contexto del tenant a partir del token validado, no de un tenant ID enviado por el navegador.
Separa la autenticación de la autorización
Cognito responde:
¿Quién es este usuario?
Tu aplicación todavía debe responder:
¿Qué puede hacer este usuario dentro de este tenant?
No trates la posesión de un token válido de Cognito como permiso para acceder a todos los recursos del tenant.
Un contexto de autorización útil podría contener:
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "tenant_123",
"roles": ["admin"]
}
sub es el identificador de usuario de Cognito. tenant_id establece el límite del tenant. roles representa los permisos de la aplicación.
Los grupos de Cognito pueden ser útiles para roles generales, pero crear un grupo para cada combinación de tenant y rol se vuelve difícil de gestionar a medida que crece el número de tenants. Para sistemas más grandes, la membresía del tenant y los roles pueden mantenerse en los datos de la aplicación y proyectarse en los claims de autorización cuando sea necesario.

Un patrón práctico de implementación
1. Autentica con un único User Pool de Cognito
Para muchas aplicaciones SaaS, un único User Pool puede dar servicio a múltiples tenants. Cada usuario está asociado con un identificador de tenant.
Usar User Pools separados puede ofrecer una separación administrativa más fuerte, pero también agrega sobrecarga operativa.
2. Coloca el contexto del tenant en la identidad autenticada
Almacena o deriva un identificador de tenant para cada usuario.
No confíes en esta solicitud:
GET /bookings?tenantId=tenant_456
para decidir a qué tenant puede acceder quien llama.
En su lugar, extrae el identificador del tenant desde el JWT validado.
3. Valida el token en el límite de la API
API Gateway puede validar los JWTs emitidos por Cognito antes de invocar la lógica de la aplicación. El backend luego utiliza los claims validados que provee el authorizer.
4. Aplica el aislamiento de tenants en cada operación de datos
Supongamos que DynamoDB almacena citas.
Un diseño de clave útil es:
PK = TENANT#tenant_123
SK = APPOINTMENT#abc123
El backend construye la partition key a partir del claim de tenant autenticado.
Un handler de Lambda simplificado podría contener:
const claims = event.requestContext.authorizer.jwt.claims;
const tenantId = claims["tenant_id"];
if (!tenantId) {
throw new Error("Missing tenant context");
}
const pk = `TENANT#${tenantId}`;
El cliente nunca decide la partition key.
5. Aplica las verificaciones de rol por separado
La membresía del tenant responde dónde puede operar el usuario. Los roles responden qué puede hacer el usuario.
Por ejemplo:
memberpuede ver citas.managerpuede modificar horarios.adminpuede gestionar personal.
Mantén estas verificaciones explícitas en la lógica de negocio o en una capa de autorización compartida.
Ejemplo: SaaS de reserva de citas
Considera una plataforma utilizada por negocios independientes.
María trabaja para tenant_123. Inicia sesión a través de Cognito y recibe un token que contiene su identidad, el contexto de tenant y su rol.
Ella solicita:
GET /appointments
API Gateway valida el token. La función Lambda lee tenant_123 desde los claims autenticados y consulta únicamente la partición de DynamoDB correspondiente a ese tenant.
Si María modifica la solicitud del navegador y envía tenant_456, el backend lo ignora. Si la API expone una ruta como /tenants/{tenantId}/appointments, el backend compara el tenant de la ruta con el tenant autenticado antes de acceder a los datos.
Esa verificación es el verdadero límite entre tenants.

Compensaciones y errores comunes
Confiar en los tenant IDs provistos por el cliente
Un tenant ID en un parámetro de solicitud es una entrada de datos, no una identidad. El contexto del tenant debe provenir de una fuente de autenticación validada.
Usar los grupos de Cognito como modelo completo de autorización
Los grupos funcionan bien para roles simples, pero los permisos de una aplicación SaaS pueden involucrar membresía específica por tenant, propiedad de recursos o acceso delegado. Esas reglas generalmente pertenecen a un modelo de autorización de la aplicación.
Asegurar la API pero no el modelo de datos
Diseña las claves de DynamoDB, los predicados SQL o los métodos del repositorio en torno al contexto del tenant, de modo que el aislamiento se aplique de forma consistente.
Colocar demasiada información en los tokens
Los claims de JWT son convenientes, pero los tokens permanecen válidos durante un período de tiempo. Por lo tanto, un cambio de rol puede no reflejarse hasta que se emita un nuevo token. El estado de autorización que cambia con frecuencia puede necesitar verificarse contra los datos de la aplicación en su lugar.
Conclusión
Cognito puede resolver la parte de identidad de la autenticación multi-tenant, pero el aislamiento de tenants sigue siendo una responsabilidad de la arquitectura de la aplicación. Trata el identificador del tenant como contexto de seguridad confiable, valídalo en el límite de la API, y llévalo a cada decisión de acceso a datos.
Como siguiente paso, traza una operación de API desde el token de Cognito hasta la consulta de base de datos, y verifica que ningún identificador de tenant controlado por el cliente pueda cambiar los recursos a los que accede.