Desarrollo Web 5-8 minutos

Passkeys en Laravel 13: autenticación sin contraseña con WebAuthn, paso a paso

Diego Cortés
Diego Cortés
Full Stack Developer & SEO Specialist
Compartir:
Passkeys en Laravel 13: autenticación sin contraseña con WebAuthn, paso a paso

Laravel 13, lanzado en marzo de 2026, incorpora soporte nativo de passkeys: tus usuarios pueden entrar con la huella, Face ID o una llave de seguridad, sin contraseña y con WebAuthn de serie. Esta guía te muestra cómo montarlo con Fortify de principio a fin.

Por qué las passkeys están reemplazando a las contraseñas

Las passkeys son la evolución lógica del login clásico. En lugar de un secreto que el usuario memoriza y que el servidor guarda (la contraseña), la autenticación se apoya en criptografía de clave pública: el dispositivo del usuario conserva la clave privada y el servidor solo almacena la pública. El resultado es que no hay ningún secreto compartido que robar en una brecha de datos, y el inicio de sesión se vuelve resistente al phishing por diseño.

Qué es WebAuthn y cómo funciona una passkey

WebAuthn es el estándar del W3C, basado en FIDO2, que permite a los navegadores gestionar estas credenciales. Una passkey es una credencial WebAuthn vinculada a un dispositivo o a un gestor de contraseñas en la nube, desbloqueable con biometría, PIN o una llave de seguridad física. El flujo se divide en dos ceremonias: la attestation, donde el usuario registra la credencial, y la assertion, donde la usa para autenticarse. En ambas, el navegador hace el trabajo pesado y tu aplicación solo recibe los datos verificables.

Ventajas frente a contraseña + 2FA tradicional

El 2FA por código (SMS o aplicación) reduce el riesgo de robo de contraseña, pero sigue dependiendo de un secreto que se puede interceptar o suplantar. Las passkeys eliminan el problema de raíz: al no existir un código escribible ni un secreto compartido, el phishing no tiene nada que robar, aunque el usuario caiga en un sitio falso. Además, la experiencia mejora: entrar con huella es más rápido que teclear una contraseña y un código de seis dígitos.

Passkeys en Laravel 13: qué aporta el framework

Laravel 13, cuyo nombre en clave es Atlas, se publicó el 17 de marzo de 2026 y trajo la autenticación con passkeys como una de sus novedades destacadas. No hace falta montar servicios de terceros ni integrar paquetes de la comunidad: el soporte oficial llega integrado en el ecosistema del framework.

Soporte nativo con Fortify y el paquete laravel/passkeys

La implementación se apoya en Fortify, el paquete oficial de autenticación de Laravel. Fortify envuelve el paquete Composer laravel/passkeys y lo configura automáticamente; las opciones se definen en config/fortify.php de tu aplicación. Si ya usas Fortify para el login clásico, activar passkeys es un cambio de configuración, no una reescritura.

Requisitos: PHP 8.3 y cero breaking changes desde Laravel 12

Laravel 13 exige PHP 8.3 como mínimo y presumió de cero breaking changes: la mayoría de aplicaciones actualizan sin tocar código de aplicación. Si vienes de Laravel 12, la actualización es el primer paso natural, y el resto de esta guía funciona tal cual sobre la versión 13.

Instalación y configuración

Empieza instalando Fortify y publicando su configuración:

composer require laravel/fortify
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"

Después, en config/fortify.php, activa el soporte de passkeys en la sección correspondiente y registra el service provider de Fortify en bootstrap/providers.php si tu proyecto no lo tiene. El paquete laravel/passkeys se instala y configura de forma automática a través de Fortify, así que no necesitas publicar migraciones ni controladores adicionales para arrancar.

Registro de una passkey: el flujo de attestation

El registro es la primera de las dos ceremonias de WebAuthn. Tu servidor genera una opción de registro con un challenge aleatorio, el navegador la convierte en una credencial nueva y el servidor la guarda asociada al modelo User.

Generar la opción de registro desde el servidor

En una ruta protegida, devuelves la opción de registro generada por laravel/passkeys, que incluye el challenge y los parámetros del RP (relying party), es decir, tu dominio. El JavaScript del cliente la consume con la API estándar del navegador:

const options = await fetch('/passkeys/register/options', {
  headers: { 'Accept': 'application/json' }
}).then(r => r.json());

const credential = await navigator.credentials.create({ publicKey: options });

Guardar la credencial asociada al modelo User

El objeto credential que devuelve el navegador contiene el id, la clave pública y los datos de attestation. Lo envías a una ruta POST que lo valida y almacena la credencial vinculada al usuario autenticado. A partir de ese momento, ese dispositivo puede usarse para entrar sin contraseña.

Login con passkey: el flujo de assertion

La segunda ceremonia, la assertion, es la que ocurre cada vez que un usuario entra con su passkey. El servidor genera una opción de autenticación, el navegador la resuelve con la clave privada del dispositivo y el servidor verifica la firma contra la clave pública guardada.

Verificar la credencial y abrir sesión

En el cliente, la llamada es simétrica a la del registro:

const options = await fetch('/passkeys/authenticate/options', {
  headers: { 'Accept': 'application/json' }
}).then(r => r.json());

const assertion = await navigator.credentials.get({ publicKey: options });

El assertion se envía al servidor, que comprueba la firma y el challenge, localiza al usuario por la credencial y abre la sesión. Todo el intercambio criptográfico queda en manos de WebAuthn; tu aplicación solo orquesta el flujo.

Combinar passkeys con el 2FA de Fortify

Desde julio de 2026, Laravel News documenta el sign-in sin contraseña combinado con el segundo factor de Fortify. La combinación es potente para apps sensibles: la passkey sustituye a la contraseña, y el 2FA de Fortify añade una capa extra de verificación cuando quieres exigirla. El resultado es un login sin contraseña que además conserva la protección adicional donde la necesitas.

Ejemplo práctico: login sin contraseña completo

El flujo completo sobre Laravel 13 se reduce a cuatro piezas: una ruta que sirve la vista de login, una ruta que genera la opción de registro, una ruta que guarda la credencial y una ruta que verifica la assertion y autentica al usuario. La vista Blade incluye los dos snippets de JavaScript anteriores: un botón de registrar passkey para usuarios logueados y un botón de entrar con passkey para el login. Con la configuración de Fortify activada y el modelo User con su relación de credenciales, la integración queda completa sin servicios externos.

Seguridad y compatibilidad

Navegadores y dispositivos soportados

WebAuthn está soportado por los navegadores principales: Chrome, Safari, Edge y Firefox en sus plataformas actuales. Las passkeys funcionan con biometría en móviles (huella y Face ID), con Windows Hello en escritorio, con los llaveros en la nube de Apple y Google, y con llaves de seguridad hardware como YubiKey. La compatibilidad exacta depende del navegador y del sistema operativo del usuario, así que conviene probar el flujo en los que use tu audiencia.

Fallbacks y recuperación de cuenta si se pierde el dispositivo

Una passkey no se puede recuperar desde el servidor: la clave privada vive en el dispositivo del usuario. Por eso, antes de lanzar, necesitas un plan de recuperación: correo de verificación, códigos de respaldo o el 2FA de Fortify como vía alternativa. Lo habitual es ofrecer passkeys como opción principal y mantener un fallback clásico para los casos límite, de modo que ningún usuario se quede fuera de su cuenta.

Conclusión

Laravel 13 convierte las passkeys en una opción realista para cualquier aplicación: soporte nativo vía Fortify, cero servicios de terceros y un flujo WebAuthn estándar que el navegador gestiona por ti. La autenticación sin contraseña no es solo una mejora de seguridad, también es una mejora de experiencia, y con el respaldo del framework el coste de implementación es pequeño. Si quieres seguir al día con Laravel, PHP y desarrollo web, no te pierdas el resto de artículos del blog.

Categorías