Settings → Account → Passkeys: the Manage page fails with a server error for anyone who has a passkey #424

Closed
opened 2026-10-01 10:46:36 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, by rendering every allauth page the account settings link to.

Related to #47.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at accounts/settings_views.py:198 (passkeys_url); the other locations have not moved.

allauth's passkey list page loads the humanize template library, and django.contrib.humanize is not installed. The page cannot be compiled, so everybody who has added a passkey and presses Manage gets a 500. That page is the only way to rename or remove a passkey, so a passkey on a lost or stolen device cannot be revoked from the interface.

  • Where: config/settings/base.py:37-73 (INSTALLED_APPS has no django.contrib.humanize); accounts/settings_views.py:196 (passkeys_url = reverse("mfa_list_webauthn")); templates/settings/account.html:105-109 (the Manage link, shown whenever passkeys.count is non-zero). The failing template is allauth's own mfa/webauthn/authenticator_list.html, whose fifth line is {% load humanize %} (it uses |naturaltime); Postulo overrides only templates/mfa/base_entrance.html and templates/mfa/base_manage.html.
  • What happens: a person with one passkey opens Settings → Account (200) and presses Manage. GET /accounts/2fa/webauthn/ raises TemplateSyntaxError: 'humanize' is not a registered tag library, and the person sees a server error. The per-key Remove and Edit views are linked only from that page, and both redirect back to it on success (success_url = reverse_lazy("mfa_list_webauthn") in allauth's RemoveWebAuthnView and EditWebAuthnView), so even a remove that goes through ends on the error page. Checked against allauth 65.19.5 (installed, and pinned in uv.lock today) and 65.19.2 (pinned when the review began); both load humanize there.
  • Why it matters: revoking a passkey is how somebody shuts out a device they no longer control. Today they cannot, short of an administrator deleting rows by hand. No unit or browser test visits the list page: tests/e2e/test_passkeys.py adds a passkey and signs in with it, and never opens Manage.
  • Fix: add "django.contrib.humanize" to INSTALLED_APPS (it has no models and no migrations). Alternatively override templates/mfa/webauthn/authenticator_list.html without humanize, in Postulo's own layout, which the override would want anyway. allauth's usersessions/usersession_list.html loads it too, should that app ever be installed.

Done when

  • A test in tests/test_allauth_layout.py gives a user one Authenticator of type WEBAUTHN, requests reverse("mfa_list_webauthn") and gets 200 with the passkey's name on the page; it fails today with TemplateSyntaxError.
  • The same file renders every allauth page Postulo links to from Settings → Account (mfa_index, mfa_list_webauthn, mfa_add_webauthn, the recovery codes and TOTP pages) for a user who has each kind of authenticator, so a template library allauth adds later fails a test rather than a person.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, by rendering every allauth page the account settings link to. Related to #47. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `accounts/settings_views.py:198` (`passkeys_url`); the other locations have not moved. allauth's passkey list page loads the `humanize` template library, and `django.contrib.humanize` is not installed. The page cannot be compiled, so everybody who has added a passkey and presses *Manage* gets a 500. That page is the only way to rename or remove a passkey, so a passkey on a lost or stolen device cannot be revoked from the interface. - **Where:** `config/settings/base.py:37-73` (`INSTALLED_APPS` has no `django.contrib.humanize`); `accounts/settings_views.py:196` (`passkeys_url = reverse("mfa_list_webauthn")`); `templates/settings/account.html:105-109` (the *Manage* link, shown whenever `passkeys.count` is non-zero). The failing template is allauth's own `mfa/webauthn/authenticator_list.html`, whose fifth line is `{% load humanize %}` (it uses `|naturaltime`); Postulo overrides only `templates/mfa/base_entrance.html` and `templates/mfa/base_manage.html`. - **What happens:** a person with one passkey opens *Settings → Account* (200) and presses *Manage*. `GET /accounts/2fa/webauthn/` raises `TemplateSyntaxError: 'humanize' is not a registered tag library`, and the person sees a server error. The per-key *Remove* and *Edit* views are linked only from that page, and both redirect back to it on success (`success_url = reverse_lazy("mfa_list_webauthn")` in allauth's `RemoveWebAuthnView` and `EditWebAuthnView`), so even a remove that goes through ends on the error page. Checked against allauth 65.19.5 (installed, and pinned in `uv.lock` today) and 65.19.2 (pinned when the review began); both load `humanize` there. - **Why it matters:** revoking a passkey is how somebody shuts out a device they no longer control. Today they cannot, short of an administrator deleting rows by hand. No unit or browser test visits the list page: `tests/e2e/test_passkeys.py` adds a passkey and signs in with it, and never opens *Manage*. - **Fix:** add `"django.contrib.humanize"` to `INSTALLED_APPS` (it has no models and no migrations). Alternatively override `templates/mfa/webauthn/authenticator_list.html` without `humanize`, in Postulo's own layout, which the override would want anyway. allauth's `usersessions/usersession_list.html` loads it too, should that app ever be installed. ## Done when - A test in `tests/test_allauth_layout.py` gives a user one `Authenticator` of type `WEBAUTHN`, requests `reverse("mfa_list_webauthn")` and gets 200 with the passkey's name on the page; it fails today with `TemplateSyntaxError`. - The same file renders every allauth page Postulo links to from *Settings → Account* (`mfa_index`, `mfa_list_webauthn`, `mfa_add_webauthn`, the recovery codes and TOTP pages) for a user who has each kind of authenticator, so a template library allauth adds later fails a test rather than a person.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:46:36 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#424
No description provided.