Skip to content

Commit f34b363

Browse files
committed
Add how-to documentation about using
`render_otp_webauthn_sync_signals_scripts`
1 parent 36789b4 commit f34b363

File tree

3 files changed

+135
-7
lines changed

3 files changed

+135
-7
lines changed

docs/how_to_guides/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ Here are what you will find in this section:
2525

2626
Learn how to configure WebAuthn to work across multiple domains. For example, if your main application runs on ``https://example.com`` and you have a localized version on ``https://example.co.uk``.
2727

28+
.. grid-item-card:: :ref:`Keeping Passkeys up-to-date with changing user details <keeping_passkeys_in_sync>`
29+
30+
Learn how to keep Passkey user details saved in users' browsers up-to-date when details like email or username change.
31+
2832
.. toctree::
2933
:maxdepth: 2
3034
:hidden:
@@ -33,3 +37,4 @@ Here are what you will find in this section:
3337
Customize helper class <customize_helper_class.rst>
3438
Customize models <customize_models.rst>
3539
Configure related origins <configure_related_origins.rst>
40+
Keeping Passkeys up-to-date with changing user details <keeping_passkeys_in_sync.rst>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
.. _keeping_passkeys_in_sync:
2+
3+
Keeping user details in sync with Passkeys
4+
==========================================
5+
6+
When your users make changes to their details, such as their email address or
7+
username, these changes won't automatically be reflected in the Passkeys they
8+
have saved in their browser. This can lead to confusion as their old email or
9+
username may still appear during Passkey authentication.
10+
11+
To ensure a smooth user experience, it's important to keep the user details
12+
associated with Passkeys up to date. Django OTP WebAuthn has a template tag that
13+
can help with this by calling the right browser APIs to update the stored
14+
Passkeys for you.
15+
16+
17+
.. _the_render_otp_webauthn_sync_signals_scripts_template_tag:
18+
19+
The ``render_otp_webauthn_sync_signals_scripts`` template tag
20+
-------------------------------------------------------------
21+
22+
This is a lightweight template tag that you can add to your base template. It
23+
looks for a key in the session that indicates that user details have changed,
24+
and if so, it renders the necessary JavaScript to update the stored Passkeys in
25+
the user's browser. If no syncing is needed, it outputs nothing.
26+
27+
To use this template tag, you would add it near the bottom of your base
28+
template, just before the closing ``</body>`` tag. This way it won't block the
29+
initial page load, but will still be executed when the page is fully loaded.
30+
31+
.. code-block:: html
32+
33+
<!-- base.html -->
34+
{% load otp_webauthn %}
35+
...
36+
<html>
37+
...
38+
<body>
39+
...
40+
...
41+
{% render_otp_webauthn_sync_signals_scripts %}
42+
</body>
43+
</html>
44+
45+
How it works
46+
------------
47+
48+
When a user authenticates using a Passkey or registers a new Passkey, the
49+
default authentication and registration views will automatically call
50+
``django_otp_webauthn.utils.request_user_details_sync`` after successful
51+
registration or authentication. This function sets a flag in the user's session
52+
indicating that their details need to be synchronized. This is the official way
53+
to request a user details sync from Django OTP WebAuthn.
54+
55+
On the next page load, when templates are being rendered, the template tag sees
56+
this flag and outputs JavaScript code that uses the appropriate WebAuthn API to
57+
update the stored Passkeys with the latest user details. After the
58+
synchronization is complete, the flag is cleared from the session to prevent
59+
rendering unnecessary the JavaScript on subsequent page loads.
60+
61+
62+
63+
How to trigger user details sync
64+
--------------------------------
65+
66+
To trigger the user details synchronization process, you need to call the
67+
``request_user_details_sync`` utility function whenever a user's details are
68+
updated. For example, if you have a view that allows users to update their email
69+
address or username, you would add a call to this function after the update is
70+
successful. This will ensure that the next time the user loads a page with the
71+
template tag, their Passkeys will be updated with the new details.
72+
73+
.. code-block:: py
74+
75+
# your_app/views.py
76+
from django_otp_webauthn.utils import request_user_details_sync
77+
78+
def update_user_details(request):
79+
if request.method == "POST":
80+
# Assume we have a form that updates user details
81+
form = UserDetailsForm(request.POST, instance=request.user)
82+
if form.is_valid():
83+
form.save()
84+
# Request user details sync after updating details
85+
request_user_details_sync(request)
86+
# Redirect or render success response
87+
return redirect("profile")
88+
else:
89+
form = UserDetailsForm(instance=request.user)
90+
return render(request, "update_user_details.html", {"form": form})
91+
92+
By following these steps, you can ensure that your users' Passkeys remain
93+
up to date with their latest details.
94+
95+
You won't see any visible messages or indicators when the synchronization occurs, as
96+
it happens silently in the background. However, you can check your browser's
97+
console for any errors or logs related to the synchronization process if needed.
98+
99+
How does this work from a technical perspective?
100+
------------------------------------------------
101+
102+
The ``render_otp_webauthn_sync_signals_scripts`` template tag is a convenience
103+
wrapper that ends up calling the
104+
``PublicKeyCredential.signalAllAcceptedCredentials`` and
105+
``PublicKeyCredential.signalCurrentUserDetails`` WebAuthn browser APIs. It
106+
automatically retrieves a list of currently registered credentials and the
107+
current user details in the format these APIs expect.
108+
109+
For more information about these APIs, refer to the following resources:
110+
111+
- `signalCurrentUserDetails <https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/signalCurrentUserDetails_static>`_
112+
- `signalAllAcceptedCredentials <https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/signalAllAcceptedCredentials_static>`_
113+
114+
.. note::
115+
116+
As of November 2025, these APIs are still relatively new and don't enjoy
117+
broad support from all browsers. Please see `Web authentication signal
118+
methods on caniuse.com <https://caniuse.com/wf-webauthn-signals>`_ for the
119+
most up-to-date browser support information.

docs/wordlist.txt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
AbstractWebAuthnAttestation
22
AbstractWebAuthnCredential
3+
APIs
34
auth
45
authenticator
56
authenticator's
@@ -13,42 +14,45 @@ BeginCredentialRegistrationView
1314
biometric
1415
biometrics
1516
Caddy
17+
caniuse
1618
ccTLD
1719
CompleteCredentialAuthenticationView
1820
CompleteCredentialRegistrationView
1921
cryptographic
2022
django
21-
Frontend
2223
frontend
24+
Frontend
2325
Furo
2426
gettext
2527
github
26-
http
2728
htmlcov
29+
http
2830
HTTPS
2931
js
3032
JSON
3133
localhost
3234
OneToOneField
35+
otp
3336
OTP
3437
OTPMiddleware
35-
otp
3638
passwordless
3739
pradyunsg
3840
pre
39-
PyPI
4041
py
42+
PyPI
4143
Quickstart
44+
residentKey
45+
reStructuredText
4246
rpID
4347
rpIDs
44-
reStructuredText
45-
residentKey
48+
signalAllAcceptedCredentials
49+
signalCurrentUserDetails
4650
Stormbase
4751
subclasses
4852
subclassing
4953
untrusted
50-
WebAuthn
5154
webauthn
55+
WebAuthn
5256
WebAuthn's
5357
WebAuthnCredential
5458
WebAuthnUserHandle

0 commit comments

Comments
 (0)