Autenticación sin contraseñas con WebAuthn para mejorar seguridad, UX y conversión en proyectos Node.js + React
¿Por qué Passkeys ahora?
Las passkeys (FIDO2/WebAuthn) eliminan contraseñas y evitan phishing al verificar criptográficamente al usuario y al dominio. Resultado: menos fraudes, menos tickets de “olvidé mi contraseña” y más conversiones por un login de un toque (biometría o PIN del sistema).
Arquitectura básica en MERN
- Frontend (React): usa navigator.credentials.create() para registro y navigator.credentials.get() para login.
- Backend (Node/Express): genera y valida challenges WebAuthn, guarda credentialId/publicKey/counter por usuario y aplica políticas (origin, rpID, user verification).
- DB (MongoDB): colecciones users y credentials con índices por userId y credentialId.
Endpoints mínimos (patrón)
Registro
- POST /webauthn/register/options → genera challenge, rpID, user, authenticatorSelection y lo devuelve al navegador.
- El navegador llama navigator.credentials.create({ publicKey: options }).
- POST /webauthn/register/verify → valida la respuesta (attestation), almacena credentialId, publicKey, counter, transports, backupState.
Inicio de sesión
- POST /webauthn/login/options → genera challenge para autenticación.
- El navegador llama navigator.credentials.get({ publicKey: options }).
- POST /webauthn/login/verify → valida (assertion), actualiza counter y emite tu JWT/Session.
Puntos críticos:
- TLS obligatorio (https).
- rpID = dominio (p. ej., midominio.com).
- origin debe coincidir exactamente (incluye subdominios).
- Rechaza respuestas con challenge expirado o ya usado.
Esquema sugerido en MongoDB
users
{
"_id": "ObjectId",
"email": "string",
"name": "string",
"status": "active|blocked",
"createdAt": "date"
}
credentials
{
"_id": "ObjectId",
"userId": "ObjectId",
"credentialId": "base64url",
"publicKey": "base64url",
"counter": 123,
"transports": ["internal","hybrid","usb","ble","nfc"],
"backupState": "synced|deviceBound|unknown",
"userVerified": true,
"createdAt": "date",
"lastUsedAt": "date"
}
Nunca guardes privateKey; solo publicKey y metadatos.
UX que sí convierte
- Registro en un paso tras crear cuenta: “Crear passkey” con explicación breve (icono de candado/huella).
- Botón primero: “Continuar con passkey” arriba; “Usar contraseña” como alternativa.
- Recuperación: códigos de respaldo y correo como fallback controlado.
- Cross-device: ofrece “Enviar aviso a mi teléfono” (autenticadores “hybrid”) cuando sea posible.
Políticas y seguridad
- User Verification = required (biometría/PIN); evita preferred si tu riesgo es alto.
- Resident Keys = required para experiencia “one-tap” sin introducir usuario.
- Activa replay protection con control de challenge y verificación de rpID/origin.
- Rate limiting por IP/usuario y detección de anomalías (ubicación/dispositivo).
- Registra AAGUID (tipo de autenticador) para auditoría y bloqueos finos si es necesario.
Estrategia de despliegue (90 días)
- Semana 1–2: piloto interno con administradores; mide éxito/falla y tiempos.
- Semana 3–6: “paridad de login”: contraseña o passkey (promueve passkey por defecto).
- Semana 7–10: incentiva migración (banner y recordatorios).
- Semana 11–12: exige passkey + fallback controlado para roles sensibles.
Métricas que debes mirar
- Adopción de passkeys (% de usuarios con ≥1 credencial).
- Tasa de éxito de login y tiempo al primer contenido tras autenticación.
- Reducción de reset de contraseñas y tickets de soporte.
- Fraude evitado (accesos rechazados por verificación de dominio).
Checklist operativo
- HTTPS + HSTS y orígenes claros (prod, preprod).
- Rotación y TTL de challenges.
- Índices Mongo: credentialId único, userId compuesto con lastUsedAt.
- JWT con tiempos cortos y refresh tokens con rotación.
- Monitoreo de counter (evita regresiones → sospecha de clonación).
- Plan de soporte al usuario (cambiar de dispositivo, pérdida, nuevos equipos).
Errores comunes (y solución)
- Falla de origin/rpID: revisa dominios y subdominios; evita mezclar www. y raíz sin configurar.
- CORS bloqueando opciones: habilita credentials: 'include' y cabeceras adecuadas.
- Multi-tenant: genera rpID por dominio o sincera el modelo de tenants con tu capa WebAuthn.
- Testing local: usa localhost (permitido por WebAuthn) y certificados válidos en entornos previos.
¿Quieres sumar passkeys a tu app MERN sin dolores de cabeza?
En www.SiteSupremacy.com implementamos WebAuthn extremo a extremo: backend en Node/Express, frontend en React, hardening de seguridad, métricas y soporte.
Escríbenos y obtén un plan listo para producción con pruebas y despliegue asistido.