django-otp-webauthn
raw JSON → 0.8.0 verified Mon Apr 27 auth: no python
FIDO2 WebAuthn support for django-otp, enabling passkey authentication. Version 0.8.0 requires Python >=3.10 and Django 4.2+. Active development, monthly releases.
pip install django-otp-webauthn Common errors
error django_otp_webauthn.models.WebAuthnDevice.user.RelatedObjectDoesNotExist: WebAuthnDevice has no user. ↓
cause Migrated from django-otp's old 'user' field to generic foreign key; existing data may be missing the content_type_id.
fix
Run manage.py migrate django_otp_webauthn --fake-initial and ensure Django's content types are migrated.
error ImportError: cannot import name 'WebAuthnBackend' from 'django_otp_webauthn.backends' ↓
cause Trying to import from a version <0.5.0 where the backend was named 'WebAuthnBackend' but was later moved to 'WebAuthnAuthenticationBackend'. In 0.5.0+ it's back to 'WebAuthnBackend'.
fix
Use: from django_otp_webauthn.backends import WebAuthnBackend (for 0.5.0+), or downgrade if on older version.
error ValueError: The 'rp_id' must be a valid domain, not a URL. ↓
cause Setting OTP_WEBAUTHN_RP_ID to a URL like 'https://example.com' instead of just the domain 'example.com'.
fix
OTP_WEBAUTHN_RP_ID = 'example.com' (no scheme or path)
Warnings
breaking Starting from version 0.7.0, the model field 'webauthn_key' was renamed to 'credential_public_key'. This breaks custom code that references the old field name. ↓
fix Update any direct field references: old_obj.webauthn_key -> old_obj.credential_public_key
deprecated The setting OTP_WEBAUTHN_ALLOWED_ORIGINS is deprecated in 0.8.0; use OTP_WEBAUTHN_ORIGIN (single string) instead. ↓
fix Replace OTP_WEBAUTHN_ALLOWED_ORIGINS = ['https://example.com'] with OTP_WEBAUTHN_ORIGIN = 'https://example.com'
gotcha The 'webauthn' library (not django-otp-webauthn) uses a non-standard field name 'credential_id' in its return dict. When accessing credential data, use 'credential_id' (lowercase) not 'credentialID'. ↓
fix Always use .get('credential_id') on the response dict, not .credentialID or .get('credentialID')
Imports
- WebAuthnDevice wrong
from otp_webauthn.models import WebAuthnDevicecorrectfrom django_otp_webauthn.models import WebAuthnDevice - WebAuthnBackend wrong
from otp_webauthn.backends import WebAuthnBackendcorrectfrom django_otp_webauthn.backends import WebAuthnBackend
Quickstart
INSTALLED_APPS = [
...
'django_otp',
'django_otp_webauthn',
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'django_otp_webauthn.backends.WebAuthnBackend',
]
OTP_WEBAUTHN_RP_NAME = 'My App'
OTP_WEBAUTHN_RP_ID = 'example.com'
OTP_WEBAUTHN_ORIGIN = 'https://example.com'