diff --git a/docs/customizing_behavior/index.rst b/docs/customizing_behavior.rst similarity index 93% rename from docs/customizing_behavior/index.rst rename to docs/customizing_behavior.rst index a820372..311e52e 100644 --- a/docs/customizing_behavior/index.rst +++ b/docs/customizing_behavior.rst @@ -45,12 +45,3 @@ Customizing frontend -------------------- The frontend implementation in this library supports customization only through CSS. For any additional customization, you have to create your own implementation. As long as you call the same API endpoints and use the same JSON structure, you can still use all other components of this package, including views and models. - - -.. toctree:: - :maxdepth: 2 - :hidden: - - Customize views - Customize helper class - Customize models diff --git a/docs/glossary.rst b/docs/glossary.rst index ca31bf0..12507b8 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -9,6 +9,9 @@ Glossary authenticator An authenticator is a software or hardware implementation of the client side of the Web Authentication standard. It manages the cryptographic parts of the process. When a user registers or logs in with a credential, the browser usually presents several authenticator options. Common examples include Chrome Password Manager, a USB key, iCloud Keychain, or a smartphone. + country code top-level domain (ccTLD) + A specific type of top-level domain (TLD) that is associated with a particular country or territory. It consists of two letters and is used to identify websites related to that country. For example, ".uk" for the United Kingdom or ".de" for Germany. + credential ID A unique identifier generated by the authenticator when creating a WebAuthn credential. Credential ID consists of a random sequence of bytes and is used in negotiations between the browser and the server. @@ -34,6 +37,9 @@ Glossary relying party The entity that relies on the Web Authentication standard to authenticate users. This refers to you, as you are using Web Authentication to authenticate your users. + relying party ID (rpID) + The domain of the website or service where a passkey can be used, without including protocol, port, or path. For example, ``acbde.com``. It ties the passkey to a specific domain to prevent phishing. Subdomains match a parent rpID, but not the other way around. The rpID is included in WebAuthn login requests and verified by the browser against the current page's origin. + resident key An alternative term for a for a passkey or resident key. It refers to a WebAuthn credential that allows authentication without the server providing credential IDs. diff --git a/docs/how_to_guides/configure_related_origins.rst b/docs/how_to_guides/configure_related_origins.rst new file mode 100644 index 0000000..688655e --- /dev/null +++ b/docs/how_to_guides/configure_related_origins.rst @@ -0,0 +1,37 @@ +.. _configure_related_origins: + +Configure related origins +========================= + +You can use ``WellKnownWebAuthnView`` to configure your application to use the same :term:`WebAuthn credentials ` across multiple domains. For example, if your main application runs on ``https://example.com`` and you have localized versions on ``https://example.co.uk`` and ``https://example.de``. + +Set up the URL +-------------- + +Modify your ``/urls.py`` file and add the required URL configuration: + +.. code-block:: py + + from django.urls import path + from django_otp_webauthn.views import WellKnownWebAuthnView + + urlpatterns = [ + ... + path(".well-known/webauthn", WellKnownWebAuthnView.as_view()), + ] + +Add related origins to your Django settings +------------------------------------------- + +Now in your ``/settings.py`` file, add your related origins to ``OTP_WEBAUTHN_RP_RELATED_ORIGINS``. The related origins must use ``HTTPS``, except for localhost origins, which can use ``HTTP`` for local development: + +.. code-block:: py + + OTP_WEBAUTHN_RP_RELATED_ORIGINS = [ + "https://example.com", + "https://example.co.uk", + "https://example.de", + "https://app.example.com" + ] + +For more information, see the reference docs on :ref:`WellKnownWebAuthnView `. diff --git a/docs/customizing_behavior/customize_helper_class.rst b/docs/how_to_guides/customize_helper_class.rst similarity index 100% rename from docs/customizing_behavior/customize_helper_class.rst rename to docs/how_to_guides/customize_helper_class.rst diff --git a/docs/customizing_behavior/customize_models.rst b/docs/how_to_guides/customize_models.rst similarity index 100% rename from docs/customizing_behavior/customize_models.rst rename to docs/how_to_guides/customize_models.rst diff --git a/docs/customizing_behavior/customize_views.rst b/docs/how_to_guides/customize_views.rst similarity index 100% rename from docs/customizing_behavior/customize_views.rst rename to docs/how_to_guides/customize_views.rst diff --git a/docs/how_to_guides/index.rst b/docs/how_to_guides/index.rst new file mode 100644 index 0000000..08cd96e --- /dev/null +++ b/docs/how_to_guides/index.rst @@ -0,0 +1,35 @@ +How-to guides +============= + +This section provides step-by-step guides to help you implement key features of Django OTP WebAuthn. + +Here are what you will find in this section: + +.. grid:: 1 1 2 2 + :gutter: 3 + :margin: 0 + + .. grid-item-card:: :ref:`Customize views ` + + Learn how to subclass Django OTP WebAuthn's built-in views to customize registration and authentication behavior. For example, adding restrictions or logging mechanisms. + + .. grid-item-card:: :ref:`Customize helper class ` + + Learn how to customize the behavior of :term:`WebAuthn` in your Django application. For example, if you want to add additional fields to the credential model. + + .. grid-item-card:: :ref:`Customize models ` + + Learn how to create custom Django OTP WebAuthn models if the base models don't suit your needs. + + .. grid-item-card:: :ref:`Configure related origins ` + + 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``. + +.. toctree:: + :maxdepth: 2 + :hidden: + + Customize views + Customize helper class + Customize models + Configure related origins diff --git a/docs/index.rst b/docs/index.rst index 1fd574e..2291812 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -61,7 +61,8 @@ Head over to the :ref:`Getting started ` section to learn about :hidden: Getting started - Customizing behavior + customizing_behavior.rst + How-to guides Reference glossary.rst FAQ diff --git a/docs/reference/views.rst b/docs/reference/views.rst index 60357f4..9035ae1 100644 --- a/docs/reference/views.rst +++ b/docs/reference/views.rst @@ -32,3 +32,71 @@ CompleteCredentialAuthenticationView The system also checks other requirements, such as whether the :term:`authenticator` performed user verification by prompting for a PIN, password, or fingerprint, if requested. Finally, the system logs in the user associated with the ``WebAuthnCredential`` and marks them as having passed 2FA authentication. + +.. _wellknownwebauthnview: + +WellKnownWebAuthnView +--------------------- + +``WellKnownWebAuthnView`` supports :term:`WebAuthn` across related origins. The view permits public access, doesn't require authentication, and accepts only ``GET`` requests. It also accepts origins that use ``https`` or ``http://localhost`` for local development, and caches responses for 10 minutes. + +Use cases +~~~~~~~~~ + +Two use cases necessitate allowing requests from related origins. + +The first use case is deployments that use different :term:`country code top-level domains (ccTLD) ` worldwide. For example, a grocery website might use ``https://grocery.com`` for users in the United States, ``https://grocery.co.uk`` for the United Kingdom, and ``https://grocery.de`` for Germany. + +The second use case is for organizations that offer additional services with different or extended branding and share the same accounts. For example, a grocery website may have a website for taking orders from buyers and a separate website for tracking delivery. + +How it works +~~~~~~~~~~~~ + +``WellKnownWebAuthnView`` works by allowing a :term:`relying party` to provide a list of valid origins for a given :term:`relying party ID (rpID)`. + +During a WebAuthn operation, the browser checks whether the current origin matches the rpID. If the origin and rpID differ, and the browser supports related origin requests, the browser queries the ``/.well-known/webauthn`` endpoint hosted at the rpID. The server responds with a JSON document that includes a top-level ``origins`` key, with a list of related origins as its value. The browser verifies the list and continues with authentication if the current origin is included. + +The browser processes this list using **labels**. A label refers to the part of the domain directly preceding the top-level domain. For example, ``grocery`` is the label for domains like ``https://grocery.com``, ``https://grocery.co.uk``, and ``https://grocery.de``. This grouping allows browsers to support origin lists efficiently without processing excessive unique entries. + +Client implementations shouldn't support more than five labels. So if the list contains 30 domains that all share the label ``grocery``, the browser counts these as a single unique label. + +Configuration +~~~~~~~~~~~~~ + +To support related origins, define the list of allowed origins in the ``OTP_WEBAUTHN_RP_RELATED_ORIGINS`` setting. Each origin must use ``https``, except for ``http://localhost`` during development. + +Also, a JSON document must be hosted at the WebAuthn well-known path for the rpID, ``/.well-known/webauthn``. For example, if the rpID is ``grocery.com``, the full URL would be ``https://grocery.com/.well-known/webauthn``. The server must also respond with a content type of ``application/json``. The JSON response must contain the list of related origins configured in ``OTP_WEBAUTHN_RP_RELATED_ORIGINS`` in the ``/settings.py`` file. + +Here is an example configuration in the ``/settings.py`` file: + +.. code-block:: py + + OTP_WEBAUTHN_RP_RELATED_ORIGINS = [ + "https://grocery.com", + "https://grocery.co.uk", + "https://grocery.de", + ] + +The JSON response will look like this: + +.. code-block:: json + + { + "origins": [ + "https://grocery.com", + "https://grocery.co.uk", + "https://grocery.de", + ] + } + +Choosing rpID +~~~~~~~~~~~~~ + +The most important decision when configuring your application for related origins is choosing a primary rpID. All related origins must use the primary rpID for authentication. You should select the domain most closely tied to your brand, usually the ``.com`` domain. + +Existing deployments that already use multiple rpIDs face different challenges. The system must maintain backward compatibility while implementing the related origins feature. Users with passkeys tied to the local rpID can continue normal operations, while those with credentials from other origins require additional steps. The solution requires each existing rpID to serve its well-known WebAuthn document listing all authorized origins. The backend must track which rpID created each passkey through explicit metadata or derived information. The login interface must handle cases where automatic recognition fails by implementing username-based lookup flows that redirect users to the correct authentication endpoint. + +Browser compatibility +~~~~~~~~~~~~~~~~~~~~~ + +All deployments must account for browser compatibility since not all browsers support related origin requests. The system should detect browser capabilities and provide fallback authentication methods when needed. For the list of supported browsers, see `Matrix `_.