main content

Cómo implementar autenticación y control de acceso seguro en una aplicación web a medida

He visto producción arder por culpa de un login mal pensado más veces de las que me gustaría admitir. Y casi siempre por la misma razón: la autenticación se trató como un módulo que "ya pondremos al final". Mala idea. Cómo implementar autenticación y control de acceso seguro en una aplicación web a medida no es una capa cosmética sobre la app; es una decisión arquitectónica que condiciona el modelo de datos, el despliegue, el coste operativo y, sobre todo, qué tipo de incidentes vas a tener dentro de seis meses.

En proyectos reales nos encontramos algo que en CMS o SaaS estándar no ocurre: no hay un módulo predefinido que te empuje a hacerlo de una forma concreta. Esa libertad es buena hasta que te das cuenta de que cada decisión es tuya y que el equipo de seguridad va a auditar el resultado. Por eso, antes de tocar una sola línea, conviene cerrar el modelo mental: qué autenticamos, qué autorizamos y dónde vive cada cosa.

Autenticación y autorización no son lo mismo

Lo recuerdo porque sigue confundiéndose en reuniones técnicas.

La autenticación responde a "¿quién eres?". Identidad. Punto. Un par email/contraseña, una passkey o un JWT firmado por un IdP externo. Es el portero de la entrada.

La autorización responde a "¿qué puedes hacer una vez dentro?". Permisos sobre recursos. Quién puede leer la tabla invoices, quién puede borrar usuarios, quién puede exportar un CSV con datos personales.

Mezclar ambos en el mismo middleware es la forma más rápida de acabar con un sistema que nadie entiende a los seis meses. Sepáralos en código, sepáralos en logs, sepáralos en tests.

Estrategias de autenticación que sobreviven a producción

Credenciales clásicas: email y contraseña

Sigue siendo válido si lo haces bien. Cuatro cosas innegociables:

  • Hashing serio: bcrypt, scrypt o Argon2. Argon2id si arrancas hoy. SHA-256 a pelo no es hashing de contraseñas, es una invitación a una rainbow table.
  • Longitud antes que complejidad: mínimo 12 caracteres. Las reglas tipo "una mayúscula, un símbolo y un número" producen Password1! en serie. La entropía está en la longitud, no en el teatro.
  • Rate limiting de verdad: 5 intentos fallidos en 15 minutos por cuenta y por IP. Y un backoff exponencial detrás. Si tu rate limiter solo cuenta por IP, un atacante con un pool de proxies se ríe.
  • No filtres existencia de usuarios: "Credenciales incorrectas" siempre. Da igual si el email existe o no. Y los tiempos de respuesta también deben ser constantes, porque el timing también filtra.

MFA, sin excusas para cuentas sensibles

La autenticación multifactor (MFA) no es opcional para roles administrativos. Las opciones que veo en proyectos serios:

  • TOTP (Google Authenticator, Authy, 1Password): código de 6 dígitos cada 30 segundos. Es el mínimo aceptable en B2B.
  • SMS: cómodo, pero con SIM swapping documentado en España. Útil como respaldo para usuarios no técnicos, nunca como único segundo factor en cuentas con poder.
  • WebAuthn/FIDO2: passkeys, YubiKey, Touch ID, Windows Hello. Resistente a phishing por diseño. Si tu aplicación maneja datos sensibles, esto es a donde vas.
  • Magic links: bien para apps de baja fricción, pero ojo con la expiración y el binding al dispositivo que solicitó el enlace.

Mi regla rápida: TOTP obligatorio para cualquier rol con permisos de escritura sobre datos críticos, WebAuthn ofrecido como upgrade.

OAuth 2.0 y OpenID Connect cuando hay terceros

OAuth 2.0 con OIDC encima es lo estándar para login con Google, Microsoft Entra ID o Apple. Tres cosas que se me caen en code review constantemente:

  • Usa Authorization Code con PKCE. El flujo implícito está deprecado y por buenas razones.
  • Valida el ID token en el backend. Firma, issuer, audience, expiración. No te fíes del frontend para esto, nunca.
  • Diseña la vinculación de cuentas desde el día uno. El usuario que se registró con email/contraseña y vuelve seis meses después con "Iniciar sesión con Google" sobre el mismo email es un caso real que rompe muchas apps. Si no lo resuelves, acabas con cuentas duplicadas y soporte llorando.

Passwordless y passkeys

En 2026 ya no es experimento. Apple, Google y Microsoft soportan passkeys de forma decente. Para una aplicación web a medida nueva, diseñar passwordless desde el principio te ahorra el peso operativo de gestionar contraseñas (recuperación, expiración, rotación, soporte). No es arriesgado: es eficiente.

Modelos de control de acceso

RBAC como punto de partida

RBAC (Role-Based Access Control) cubre el 80% de las necesidades B2B. Roles, permisos asociados a roles, usuarios asociados a roles. Sencillo, auditable y suficiente. Cómo lo montamos en proyectos reales:

  • Roles y permisos en tablas, no en if user.email == "admin@..." enterrado en un controlador.
  • Permisos atados a roles, no a usuarios. Si necesitas excepciones, crea un rol para esa excepción.
  • Middleware único de autorización que se ejecuta antes de la lógica de negocio. Si el chequeo está duplicado en cada endpoint, tarde o temprano alguien lo olvida.
  • Panel de administración para gestionar roles sin desplegar. Si cada cambio requiere PR, los roles dejan de mantenerse.

ABAC cuando RBAC no llega

ABAC entra cuando las reglas dependen del contexto: hora, IP, ubicación, atributos del recurso. "El equipo de finanzas puede ver informes financieros entre las 8 y las 20, desde la VPN corporativa". Eso no se modela con roles sin acabar con una explosión combinatoria.

Empieza con RBAC. Migra a ABAC cuando empieces a crear roles del tipo editor_finanzas_horario_oficina. Esa es la señal.

Multi-tenancy: el aislamiento no es opcional

Si la aplicación sirve a varios clientes, el aislamiento entre tenants es donde se juega la reputación. Tres estrategias, con sus trade-offs:

  • Base de datos por tenant: aislamiento físico, máximo. Coste operativo alto, migraciones complicadas. Lo justifica regulación financiera o sanitaria.
  • Esquema por tenant: buen punto medio. Una sola base de datos, esquemas separados, migraciones manejables.
  • Columna tenant_id: barato, eficiente, peligroso. Cada query tiene que filtrar por tenant_id sin excepciones. Una sola consulta mal escrita filtra datos entre clientes. Si vas por aquí, blíndalo con row-level security en la base de datos, no solo con disciplina del equipo.

Sesiones, tokens y dónde guardarlos

JWT bien hecho

JWT es el estándar de facto para SPAs y APIs. El token contiene claims firmados criptográficamente. Bien. Ahora las reglas que evitan incidentes:

  • Access tokens cortos: 15-30 minutos. Si filtras un access token, la ventana de daño es acotada.
  • Refresh tokens largos en cookie httpOnly: nunca en localStorage. Cualquier XSS te vacía la cuenta si vive ahí.
  • Rotación de refresh tokens: al usar uno, lo invalidas y emites el siguiente. Si detectas reutilización del antiguo, invalida toda la familia del token. Eso te da detección de robo casi gratis.
  • Lista de revocación: para forzar logout inmediato cuando un usuario cambia contraseña, pierde el portátil o sales de un cliente. Sí, rompe la pureza "stateless" del JWT. Sí, lo necesitas igual.

Cookies de sesión, infravaloradas

Para apps server-rendered o híbridas, la cookie de sesión tradicional sigue siendo más simple y, hecha bien, más segura que muchos JWT mal montados. Flags obligatorias:

  • HttpOnly: bloquea acceso desde JavaScript.
  • Secure: solo viaja por HTTPS.
  • SameSite=Lax o Strict: mitigación de CSRF razonable por defecto.
  • Domain y Path lo más restrictivos posibles.

Seguridad alrededor del flujo de auth

Ataques que vas a recibir, te guste o no

  • CSRF: tokens anti-CSRF en formularios sensibles, validación de header Origin y cookies con SameSite.
  • XSS: Content Security Policy estricta, escapado automático del framework y sanitización de cualquier HTML rico que entre desde el usuario.
  • SQL injection: queries parametrizadas o un ORM serio. Concatenar input en SQL crudo no se discute, se borra del PR.
  • Brute force y credential stuffing: rate limiting por IP y por cuenta, detección de listas conocidas filtradas (HaveIBeenPwned), captcha progresivo y, en cuentas administrativas, bloqueo con notificación al usuario.

OWASP Top 10 sigue siendo lectura obligatoria al diseñar esto. No es un checklist, es un mapa.

Logging que sirve para investigar

Cada evento relevante de auth se registra: login correcto, login fallido, cambio de contraseña, alta o baja de MFA, cambio de rol, intento de acceso denegado. Con marca de tiempo, identificador de usuario, IP y user-agent.

Lo que no se registra nunca: contraseñas (ni hasheadas), tokens completos, valores de cookies de sesión. Trazabilidad sí, exposición de credenciales no.

RGPD y cumplimiento en España

Si tratas datos personales de usuarios en la UE, hay obligaciones concretas que tocan directamente a la autenticación y el control de acceso:

  • Mínimo privilegio: cada usuario accede solo a lo que su función requiere. Esto se demuestra con la matriz de roles y los logs.
  • Trazabilidad de accesos: tienes que poder responder "quién accedió a este registro y cuándo". Si tus logs no te dejan responder, no estás cumpliendo.
  • Notificación de brechas: 72 horas para comunicar a la AEPD. Sin un buen sistema de detección y logs, ese plazo es imposible.

Lo que ponemos en producción

Resumen sin adornos de cómo solemos cerrar este tipo de implementación en proyectos a medida:

  • Argon2id para contraseñas. TOTP obligatorio en roles administrativos. WebAuthn ofrecido como opción y empujado para clientes con perfil técnico.
  • OAuth 2.0 con PKCE para login federado, validación de token en backend, vinculación de cuentas resuelta desde el primer sprint.
  • RBAC en tablas, middleware único, panel de administración. ABAC solo donde la regla de negocio realmente lo justifica.
  • Access tokens JWT de 15 minutos, refresh tokens rotativos en cookie httpOnly, detección de reutilización para revocar familias completas.
  • Multi-tenancy con esquema por tenant si el cliente lo soporta, o columna tenant_id con row-level security activada en PostgreSQL si no.
  • Logs de seguridad separados del log de aplicación, con retención alineada al RGPD y acceso restringido.
  • Revisión periódica contra OWASP Top 10 y pruebas de penetración antes de cada release mayor.

Si estás diseñando una aplicación web a medida y quieres que la autenticación y el control de acceso aguanten una auditoría real, revisa con nosotros tu arquitectura de seguridad. Diseñamos estos sistemas con la pintura todavía húmeda de proyectos en producción, no desde la teoría.