Las contraseñas son el eslabón más débil en la seguridad de las cuentas. Pueden ser suplantadas, filtradas, reutilizadas u olvidadas. Por eso hemos añadido soporte para WebAuthn Passkeys: un método de autenticación sin contraseña resistente al phishing que es más seguro y más conveniente.

¿Qué son los Passkeys?

Los Passkeys son credenciales criptográficas almacenadas en tu dispositivo (teléfono, portátil, llave de seguridad) que reemplazan las contraseñas para la autenticación. Utilizan el estándar WebAuthn (parte de FIDO2) y ofrecen varias ventajas:

  • Resistentes al phishing - Los Passkeys están vinculados al dominio del sitio web, por lo que no pueden usarse en sitios falsos
  • Sin secretos que filtrar - Solo la clave pública se almacena en el servidor
  • Vinculados al dispositivo - La clave privada nunca sale de tu dispositivo
  • Protegidos por biometría - Típicamente asegurados por Face ID, Touch ID o Windows Hello
  • Sincronización entre dispositivos - Las plataformas modernas sincronizan los Passkeys entre dispositivos a través de cuentas de iCloud, Google o Microsoft

Nuestra implementación

Integramos el soporte de WebAuthn Passkeys en nuestra pila de autenticación existente de django-allauth, proporcionando endpoints tanto para web como para la API móvil.

Flujo de registro

Cuando un usuario registra un nuevo Passkey, el flujo funciona así:

  1. El cliente solicita opciones de registro al servidor
  2. El servidor genera un desafío con información del usuario y la parte confiable
  3. La API WebAuthn del navegador solicita al usuario (biometría o llave de seguridad)
  4. El cliente envía la credencial de vuelta al servidor
  5. El servidor verifica y almacena la clave pública
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# API endpoint to begin registration
class WebAuthnRegistrationOptionsView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        from allauth.mfa.webauthn.internal import auth as webauthn_auth

        # Generate credential creation options
        creation_options = webauthn_auth.begin_registration(
            request.user,
            passwordless=False  # Use as 2FA, not passwordless
        )

        return Response({
            "success": True,
            "creation_options": creation_options,
        })

Flujo de autenticación

Para la autenticación de dos factores usando un Passkey:

  1. El usuario completa la autenticación primaria (usuario/contraseña o inicio de sesión social)
  2. El servidor devuelve un desafío para la verificación WebAuthn
  3. El navegador solicita el Passkey (toque biométrico)
  4. La credencial se verifica contra la clave pública almacenada
  5. El usuario está completamente autenticado
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class WebAuthnVerifyView(APIView):
    def post(self, request):
        credential = request.data.get("credential")

        # Complete authentication and verify credential
        authenticator = webauthn_auth.complete_authentication(
            request.user,
            credential
        )

        # Record usage for security monitoring
        authenticator.last_used_at = timezone.now()
        authenticator.save()

        return Response({"success": True})

Gestión de Passkeys

Los usuarios pueden gestionar sus Passkeys registrados:

  • Listar todos los Passkeys con fecha de registro y último uso
  • Renombrar Passkeys para una identificación más fácil (ej., “iPhone”, “MacBook”)
  • Eliminar Passkeys (con protección contra eliminar el último autenticador)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class WebAuthnListView(APIView):
    def get(self, request):
        authenticators = Authenticator.objects.filter(
            user=request.user,
            type=Authenticator.Type.WEBAUTHN
        ).order_by("-created_at")

        return Response({
            "passkeys": [
                {
                    "id": auth.pk,
                    "name": auth.wrap().name,
                    "created_at": auth.created_at.isoformat(),
                    "last_used_at": auth.last_used_at.isoformat() if auth.last_used_at else None,
                }
                for auth in authenticators
            ]
        })

Endpoints de la API

Nuestra API REST proporciona soporte completo de WebAuthn para la aplicación móvil:

EndpointMétodoDescripción
/api/webauthn/register/options/GETObtener desafío de registro
/api/webauthn/register/complete/POSTCompletar registro
/api/webauthn/authenticate/options/GETObtener desafío de autenticación
/api/webauthn/verify/POSTVerificar credencial para 2FA
/api/webauthn/GETListar Passkeys registrados
/api/webauthn/<id>/PATCHRenombrar un Passkey
/api/webauthn/<id>/DELETEEliminar un Passkey

Consideraciones de seguridad

Códigos de recuperación

Cuando un usuario registra su primer autenticador (Passkey o TOTP), generamos automáticamente códigos de recuperación. Estos códigos de un solo uso pueden utilizarse si todos los demás métodos de autenticación no están disponibles:

1
2
if Authenticator.objects.filter(user=request.user).count() == 1:
    auto_generate_recovery_codes(request._request)

Prevención de bloqueo

Los usuarios no pueden eliminar su último Passkey si los dejaría sin ningún método de autenticación de dos factores:

1
2
3
4
if not adapter.can_delete_authenticator(authenticator):
    return Response({
        "message": "Cannot delete - you must have at least one authentication method"
    }, status=400)

Monitoreo

Rastreamos el uso de Passkeys mediante métricas de Datadog para monitoreo de seguridad:

1
2
3
increment("webauthn.registration.success")
increment("webauthn.verify.success")
increment("webauthn.verify.failed")

Compatibilidad con navegadores

WebAuthn es compatible con todos los navegadores modernos:

  • Chrome 67+
  • Firefox 60+
  • Safari 13+
  • Edge 79+
  • Chrome móvil, Safari, Firefox

Para navegadores más antiguos, los usuarios pueden seguir usando TOTP (aplicaciones de autenticación) o códigos de recuperación.

La experiencia del usuario

Añadir un Passkey toma solo segundos:

  1. Ve a Configuración → Seguridad → Autenticación de dos factores
  2. Haz clic en Añadir Passkey
  3. Nombra tu dispositivo (ej., “iPhone 15”)
  4. Autentícate con Face ID / Touch ID / Windows Hello
  5. ¡Listo! Tu Passkey está registrado

Los inicios de sesión futuros requieren solo una confirmación biométrica, sin escribir contraseñas ni copiar códigos de aplicaciones de autenticación.

Por qué elegimos Passkeys

MétodoRiesgo de phishingExperiencia de usuarioRecuperación
ContraseñasAltoMala (olvidadas, débiles)Restablecimiento por email
SMS 2FAMedio (intercambio de SIM)AceptableNúmero de teléfono
Aplicaciones TOTPBajoEntrada manual de códigoClaves de respaldo
PasskeysMuy bajoExcelenteCódigos de recuperación

Los Passkeys representan el futuro de la autenticación. Ya están soportados por las plataformas de Apple, Google y Microsoft, haciéndolos accesibles para casi todos nuestros usuarios.


¿Listo para prescindir de las contraseñas? ¡Activa los Passkeys en tu configuración de seguridad!