Problemas encontrados y soluciones aplicadas
- FIDO_SERVER_ID fijo para producción nunca funcionaba en local
Archivo: reymota/settings.py:174-178
El RP ID de WebAuthn debe coincidir con el dominio del navegador. "nc.reymota.es" no funciona en localhost. Ahora es condicional:
if LOCAL:
FIDO_SERVER_ID="localhost"
else:
FIDO_SERVER_ID="nc.reymota.es"
Además cambié FIDO_SERVER_NAME de "TestApp" a "ReyMota.es".
- passkeys.js incluido DOS VECES en el login
Archivo: templates/registration/login.html
Estaba dos veces: línea 66 (dentro del , sin allow_password) y línea 92 (al final). Eliminé la del interior del formulario.
- CRÍTICO: LoginView de Django + AuthenticationForm no pueden procesar passkeys
Archivos: reymotausers/auth.py, accounts/urls.py
El problema de raíz: Django's AuthenticationForm requiere username + password para llamar a authenticate(). El login con passkey envía el formulario sin password, así que authenticate() nunca se ejecutaba y el backend PasskeyModelBackend jamás procesaba el passkey.
Solución: Reemplacé el LoginView de Django por una vista personalizada que:
- Si el campo passkeys tiene datos → llama a authenticate(request) directamente → el backend procesa la aserción WebAuthn
- Si no → usa AuthenticationForm normal para login con email+password
Flujo que ahora funciona:
Botón "Login by Passkeys"
→ JS llama a GET /passkeys/auth/begin/ (guarda fido2_state en sesión)
→ navigator.credentials.get() → assertion
→ submit del form con passkeys=
→ loginView detecta passkeys → authenticate(request)
→ PasskeyModelBackend → auth_complete() → login()
→ redirect a principal