======== WebAuthn ======== `WebAuthn `_ is a W3C standard for supporting registration and authorization using `U2F Token `_. This document will focus on setting up WebAuthn with Djoser. If you wish to learn more about WebAuthn, head to `the WebAuthn guide `_. Configuration ============= First make sure to install ``webauthn<1.0``. You can use webauthn as "extras" when installing djoser, e.g. ``pip install djoser[webauthn]`` or ``poetry add djoser -E webauthn``. Then add ``djoser.webauthn`` to ``INSTALLED_APPS``: .. code-block:: python INSTALLED_APPS = ( 'django.contrib.auth', (...), 'rest_framework', 'djoser', 'djoser.webauthn', (...), ) Add ``djoser.webauthn.urls`` url patterns to ``urls.py``: .. code-block:: python urlpatterns = [ (...), re_path(r'^auth/webauthn/', include('djoser.webauthn.urls')), ] Endpoints ========= Signup Request -------------- Use this endpoint to get ``publicKey`` data for ``navigator.credentials.create``. Note that ``display_name`` is required by WebAuthn specification, but you can ignore it in your application. Unlike ``username``, ``display_name`` does not have to be unique. **URL**: ``/signup_request/`` +----------+---------------------------------+----------------------------------+ | Method | Request | Response | +==========+=================================+==================================+ | ``POST`` | * ``username`` | ``HTTP_200_OK`` | | | * ``display_name`` | | | | | * ``challenge`` | | | | * ``rp.name`` | | | | * ``rp.id`` | | | | * ``user.id`` | | | | * ``user.name`` | | | | * ``user.displayName`` | | | | * ``pubKeyCredParams`` | | | | * ``timeout`` | | | | * ``excludeCredentials`` | | | | * ``attestation`` | | | | * ``extensions`` | | | | | | | | ``HTTP_400_BAD_REQUEST`` | | | | | | | | * ``username`` | +----------+---------------------------------+----------------------------------+ Signup ------ Pass the result of ``navigator.credentials.create`` alongside user data to this endpoint in order to verify ``navigator.credentials.create`` result and create the user if verification passes. **URL**: ``/signup/`` +----------+---------------------------------+----------------------------------+ | Method | Request | Response | +==========+=================================+==================================+ | ``POST`` | * ``{{ settings.LOGIN_FIELD }}``| ``HTTP_201_CREATED`` | | | * ``attObj`` | | | | * ``clientData`` | * ``{{ settings.LOGIN_FIELD }}`` | | | | * ``id`` | | | | | | | | ``HTTP_400_BAD_REQUEST`` | | | | | | | | * ``non_field_errors`` | | | | * ``{{ settings.LOGIN_FIELD }}`` | +----------+---------------------------------+----------------------------------+ Login Request ------------- Use this endpoint to get ``publicKey`` data for ``navigator.credentials.create``. **URL**: ``/login_request/`` +----------+----------------------------------+-----------------------------------+ | Method | Request | Response | +==========+==================================+===================================+ | ``POST`` | * ``{{ settings.LOGIN_FIELD }}`` | ``HTTP_200_OK`` | | | | | | | | * ``challenge`` | | | | * ``allowCredentials`` | | | | * ``rpId`` | | | | * ``timeout`` | | | | | | | | ``HTTP_400_BAD_REQUEST`` | | | | | | | | * ``{{ settings.LOGIN_FIELD }}`` | +----------+----------------------------------+-----------------------------------+ Login ----- Pass the result of ``navigator.credentials.create`` alongside ``{{ settings.LOGIN_FIELD }}`` to this endpoint in order to verify ``navigator.credentials.create`` and log in the user (create the token) if verification passes. +----------+---------------------------------+----------------------------------+ | Method | Request | Response | +==========+=================================+==================================+ | ``POST`` | * ``{{ settings.LOGIN_FIELD }}``| ``HTTP_201_CREATED`` | | | * ``signature`` | | | | * ``authData`` | * ``auth_token`` | | | * ``clientData`` | | | | | | | | | ``HTTP_400_BAD_REQUEST`` | | | | | | | | * ``{{ settings.LOGIN_FIELD }}`` | | | | * ``non_field_errors`` | +----------+---------------------------------+----------------------------------+ Example app =========== You can run `Test project `_ to see a working example. Running example app ------------------- .. code-block:: bash $ git clone git@github.com:sunscrapers/djoser.git $ pip install -r requirements.txt $ cd djoser/testproject $ python manage.py migrate $ python manage.py runserver Navigate to ``http://localhost:8000/webauthn-example/`` and you should see a minimalistic example of using Djoser with WebAuthn. Feel free to take a look at ``testapp/static/js/webauthn.js`` file in order to better understand the whole flow. .. note:: ``127.0.0.1`` is not a valid `effective domain `_ and the example will not work if you navigate to ``http://127.0.0.1:8000`` instead of ``http://localhost:8000``. Also keep in mind that unless the host resolves to ``localhost``, most browsers will not allow you to use ``navigator.credentials`` if the connection is not secured with TLS.