|
| 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. |
0 commit comments