File: allauth/headless/spec/doc/description.md
Introduction
Welcome to the django-allauth API specification. This API is intended to be
consumed by two different kind of clients:
Web applications running in a browser context. For example, a
single-page React application, to which the end user can navigate using a web
browser.Applications, apps for short, executing in non-browser contexts. For example,
a mobile Android or iOS application.
The security considerations for these two usage types are different. In a
browser context, cookies play a role. Without taking special precautions, your
web application may be vulnerable to Cross-Site Request Forgery attacks. For
mobile applications, this does not apply.
The API can be used for both use cases. Differences in handling of security is
automatically adjusted for, based on the request path used to make the API call.
For example, signing up can either be done using the/_allauth/browser/v1/auth/signup or the /_allauth/app/v1/auth/signup
endpoint. For the browser usage, session cookies and CSRF protection
applies. For the app usage, cookies play no role, instead, a session token
is used. The paths of all endpoints are documented in the form of/_allauth/{client}/v1/auth/signup. Depending on the client type ({client}),
there may be slight differences in request/response handling. This is
documented where applicable.
Scope
The following functionality is all in scope and handled as part of this API:
- Regular accounts:
- Login
- Signup
- Password forgotten
- Manage email (add, remove, verify, select a different primary)
- Change password.
- Verification of email addresses.
- Two-Factor Authentication:
- Authentication using an authenticator code
- (De)activate TOTP
- (Re)generate recovery codes
- "Trust this browser"
- Third-party providers:
- Authenticate by performing a browser-level redirect (synchronous request).
- Authenticate by means of a provider token.
- Connect additional provider accounts.
- Disconnect existing provider accounts.
- Setting a password in case no password was set, yet.
- Querying additional information before signing up.
- Session management:
- Listing all sessions for a user.
- Signing out of any of those sessions.
Browser Usage
For web applications running in a browser, routing needs to be setup correctly
such that the sessions initiated at the backend are accessible in the frontend.
Routing
When using the API in a browser context, regular Django sessions are used, along
with the usual session cookies. There are several options for setting up the
routing of your application.
Single Domain Routing
With single domain, path-based routing, both your frontend and backend are
served from the same domain, for example https://app.org. You will have to
make sure that some paths are served by the frontend, and others by the backend.
Sub-domain Routing
With sub-domain based routing, the frontend and backend are served from
different domains. However, as session cookies are used, these different
domains must share common main domain.
For example, you may use app.project.org for the frontend, which
interfaces with the backend over at backend.project.org. In this
setup, Django will need to be configured with:
SESSION_COOKIE_DOMAIN = "project.org"
CSRF_COOKIE_DOMAIN = "project.org"If your organization hosts unrelated applications, for example, a CMS for
marketing purposes, on the top level domain (project.org), it is not advisable
to set the session cookie domain to project.org, as those other applications
could get access to the session cookie. In that case, it is advised to usebackend.app.project.org for the backend, and set the session cookie domain toapp.project.org.
App Usage
For app based usage, cookies play no role, yet, sessions are still used. When a
user walks through the authentication flow, a session is created. Having an
authenticated session is proof that the user is allowed to further interact with
the backend. Unauthenticated sessions are also needed to remember state while
the user proceeds to go over the required steps necessary to authenticate.
Session Tokens
Given that there is no cookie to point to the session, the headerX-Session-Token is used instead. The way of working is as follows:
If you do not have a session token yet, do not send the
X-Session-Tokenheader.When making requests, session tokens can appear in the metadata
(meta.session_token) of authentication related responses. If a session
token appears, store it (overwriting any previous session token), and ensure
to add the token to theX-Session-Tokenheader of all subsequent requests.When receiving an authentication related response with status code 410
(Gone), that is meant to indicate that the session is no longer valid.
Remove the session token and start clean.
Access Tokens
While session tokens are required to handle the authentication process,
depending on your requirements, a different type of token may be needed once
authenticated.
For example, your app likely needs access to other APIs as well. These APIs may
even be implemented using different technologies, in which case having a
stateless token, possibly a JWT encoding the user ID, might be a good fit.
In this API and its implementation no assumptions, and no (limiting) design
decisions are made in this regard. The token strategy of django-allauth is
pluggable, such that you can expose your own access token when the user
authenticates. As for as the API specification is concerned, the access token
will appear in the response of metadata (meta.access_token) of a successful
authentication request. How you can customize the token strategy can be found
over at the documentation of the allauth.headless Django application.
Responses
Unless documented otherwise, responses are objects with the following
properties:
- The
status, matching the HTTP status code. - Data, if any, is returned as part of the
datakey. - Metadata, if any, is returned as part of the
metakey. - Errors, if any, are listed in the
errorskey.
Authentication Flows
In order to become authenticated, the user must complete a flow, potentially
consisting of several steps. For example:
- A login, after which the user is authenticated.
- A Login, followed by two-factor authentication, after which the user is
authenticated. - A signup, followed by mandatory email verification, after which the user is
authenticated.
The API signals to the client that (re)authentication is required by means of a401 or 410 status code:
- Not authenticated: status
401. - Re-authentication required: status
401, withmeta.is_authenticated = true. - Invalid session: status
410. This only occurs for clients of typeapp.
All authentication related responses have status 401 or 410, and,meta.is_authenticated indicating whether authentication, or re-authentication
is required.
The flows the client can perform to initiate or complete the authentication are
communicates as part of authentication related responses. The authentication can
be initiated by means of these flows:
- Login using a local account (
login). - Signup for a local account (
signup). - Login or signup using the third-party provider redirect flow (
provider_redirect). - Login or signup by handing over a third-party provider retrieved elsewhere (
provider_token). - Login using a special code (
login_by_code). - Login using a passkey (
mfa_login_webauthn). - Signup using a passkey (
mfa_signup_webauthn).
Depending on the state of the account, and the configuration of django-allauth, the flows above
can either lead to becoming directly authenticated, or, to followup flows:
- Provider signup (
provider_signup). - Email verification (
verify_email). - Phone verification (
phone_email). - Two-factor authentication required (TOTP, recovery codes, or WebAuthn) (
mfa_authenticate). - Trust this browser (
mfa_trust).
While authenticated, re-authentication may be required to safeguard the account when sensitive actions
are performed. The re-authentication flows are the following:
- Re-authenticate using password (
reauthenticate). - Re-authenticate using a 2FA authenticator (TOTP, recovery codes, or WebAuthn) (
mfa_reauthenticate).
Security Considerations
Input Sanitization
The Django framework, by design, does not perform input sanitization. For
example, there is nothing preventing end users from signing up using <script>
or Robert'); DROP TABLE students as a first name. Django relies on its
template language for proper escaping of such values and mitigate any XSS
attacks.
As a result, any allauth.headless client must have proper XSS protection
in place as well. Be prepared that, for example, the WebAuthn endpoints could
return authenticator names as follows:
{
"name": "<script>alert(1)</script>",
"credential": {
"type": "public-key",
...
}
}File: docs/common/admin.rst
Admin
The Django admin site (django.contrib.admin) does not use Django allauth by
default. Since Django admin provides a custom login view, it does not go through
the normal Django allauth workflow.
.. warning::
This limitation means that Django allauth features are not applied to the
Django admin site:
* The admin login is not protected from being brute forced (``ACCOUNT_RATE_LIMITS``).
* Two-factor authentication is not enforced.
* Any other custom workflow that overrides the Django allauth adapter's
login method will not be applied.An easy workaround for this is to require users to login before going to the
Django admin site's login page, by adding this to urls.py (note that the following would need to be applied to
every instance of AdminSite):
.. code-block:: python
from django.contrib import admin
from allauth.account.decorators import secure_admin_login
admin.autodiscover()
admin.site.login = secure_admin_login(admin.site.login)File: docs/common/configuration.rst
Configuration
Available settings:
ALLAUTH_DEFAULT_AUTO_FIELD
Can be set to configure the primary key of all models. For
example: "hashid_field.HashidAutoField".
ALLAUTH_RATE_LIMIT_IPV6_PREFIX (default: 64)
For rate limiting purposes, IPv6 addresses are truncated to their network
prefix to prevent attackers from bypassing rate limits by rotating through
addresses within their allocated prefix. This setting controls the prefix
length. The default of 64 corresponds to a standard /64 subnet.
ALLAUTH_USER_CODE_FORMAT (default: {"numeric": False, "dashed": True, length: 8})
Controls the format of user-facing verification codes (e.g. email
verification, phone verification, login codes).
File: docs/common/email.rst
Sending Email
Emails sent (e.g. in case of password forgotten or email
confirmation) can be altered by providing your own
templates. Templates are named as follows::
account/email/email_confirmation_signup_subject.txt
account/email/email_confirmation_signup_message.txt
account/email/email_confirmation_subject.txt
account/email/email_confirmation_message.txtIn case you want to include an HTML representation, add an HTML
template as follows::
account/email/email_confirmation_signup_message.html
account/email/email_confirmation_message.htmlThe project does not contain any HTML email templates out of the box.
When you do provide these yourself, note that both the text and HTML
versions of the message are sent.
If this does not suit your needs, you can hook up your own custom
mechanism by overriding the send_mail method of the account adapter
(allauth.account.adapter.DefaultAccountAdapter).
File: docs/common/index.rst
Common Functionality
.. toctree::
:maxdepth: 1
configuration
email
templates
messages
admin
rate_limits
File: docs/common/messages.rst
Messages
The Django messages framework (django.contrib.messages) is used if
it is listed in settings.INSTALLED_APPS. All messages (as indjango.contrib.messages) are configurable by overriding their
respective template. If you want to disable a message, simply override
the message template with a blank one.
File: docs/common/templates.rst
Templates
Introduction
The templates that are offered out of the box are intentionally plain and
without any styling. We do not want to pick a side in the multitudes of frontend
styling options out there, and the look and feel typically should be adjusted to
match the branding of your project. Therefore it is recommended that you copy all
templates over to your own project and adjust them as you see fit.
Having said that, with features such as third party account providers
and two-factor authentication, adjusting the templates involves a lot more than
just styling a login.html and a signup.html template. Therefore, a
mechanism is included that allows you to adjust the look and feel of all
templates by only overriding a few core templates. This approach allows you to
achieve visual results fast, but is of course more limited compared to styling
all templates yourself.
Overriding the Built-In Templates
The allauth app includes all templates, and can be found in theallauth/templates <https://codeberg.org/allauth/django-allauth/src/branch/main/allauth/templates>__
directory. When allauth is part of your INSTALLED_APPS, and"APP_DIRS": True is configured, Django will be able to find its templates.
As DIRS is searched before APP_DIRS, overriding the templates involves
adding an entry to DIRS that points to your a project specific template
folder, as follows::
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
BASE_DIR / "templates"
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]If you copy over all templates to your BASE_DIR / "templates" it should
contain these entries (a.o.):
- An
accountfolder containing the templates from theallauth.accountapp. - A
socialaccountfolder containing the templates from theallauth.socialaccountapp. - A
mfafolder containing the templates from theallauth.mfaapp. - An
allauthfolder containing the overall styling templates (see the next section).
Styling the Existing Templates
Instead of copying all templates, a mechanism is included that allows you to
adjust the look and feel of all templates by only overriding a few core
templates. This approach allows you to achieve visual results fast, but is of
course more limited compared to styling all templates yourself.
Layouts
^^^^^^^
The existing templates use two base page layouts:
The entrance layout: These are all pages where the user is in the process of
authenticating, such as the login and signup pages.The account management layout: The pages where an authenticated user can
manage the account, such as changing the email address or password.
You can alter these layouts by providing these templates in your own project:
========================================== ===========
Template file Description
========================================== ===========
allauth/layouts/base.html The overall base template.
allauth/layouts/entrance.html The entrance template, extending the base template.
allauth/layouts/manage.html The account management template, extending the base template.
========================================== ===========
Elements
^^^^^^^^
When rendering e.g. a Bootstrap button you would typically use::
OkayYet, when a different CSS framework is used other class names apply, and
possibly even other markup. Therefore, the built-in templates do not include the
above content directly. Instead of referring to tags such ```
/* Detailed source-code truncated for AI context efficiency. */
allauth/elements/button_group.html A group of related buttons.
allauth/elements/details.html Disclosure (````).
allauth/elements/field.html A single form field.
allauth/elements/fields.html The form fields, uses ``{{form.as_p}}`` by default, hence, not rendering the ``field.html``.
allauth/elements/form.html The ``<form>`` container tag.
allauth/elements/h1.html Level 1 heading (``<h1>``).
allauth/elements/h2.html Level 2 heading (``<h2>``).
allauth/elements/hr.html Horizontal rule (``<hr>``).
allauth/elements/img.html An image tag (````).
allauth/elements/panel.html A panel (aka card), consisting of a title, body and actions.
allauth/elements/p.html Paragraphs (````).
allauth/elements/provider.html A link to a third-party provider.
allauth/elements/provider_list.html The container element for the list of third-party providers.
allauth/elements/table.html Table (````).
allauth/elements/tbody.html Table body (````).
allauth/elements/td.html Table data cell (````).
allauth/elements/th.html Table header cell (````).
allauth/elements/thead.html Table head (````).
allauth/elements/tr.html Table row (````).
========================================== ===========
Example
^^^^^^^
The source repository contains a Bootstrap styled example project, which
provides a good example of how all of the above can be put together to provide
styling without altering any of the content templates. Please take a look at
the `templates of the example project
<https://codeberg.org/allauth/django-allauth/src/branch/main/examples/regular-django/example/templates>`__.
You can see those templates live in the `running demo project
<https://django.demo.allauth.org>`__.
---
## File: docs/account/adapter.rst
Adapter
=======
.. autoclass:: allauth.account.adapter.DefaultAccountAdapter
:members:
---
## File: docs/account/advanced.rst
Advanced Usage
==============
Custom User Models
------------------
If you use a custom user model you need to specify what field
represents the ``username``, if any. Here, ``username`` really refers to
the field representing the nickname that the user uses to login, and not to
some unique identifier (possibly including an email address) as is
the case for Django's ``AbstractBaseUser.USERNAME_FIELD``.
Therefore, if your custom user model does not have a ``username`` field (again,
not to be mistaken with an email address or user id), you will need to set
``ACCOUNT_USER_MODEL_USERNAME_FIELD`` to ``None``. This will disable username
related functionality in ``allauth``. Remember to also remove username from
``ACCOUNT_SIGNUP_FIELDS`` as by default that is present.
Similarly, you will need to set ``ACCOUNT_USER_MODEL_EMAIL_FIELD`` to
``None`` or to the proper field (if other than ``email``).
For example, if you want to use a custom user model that has ``email``
as the identifying field, and you don't want to collect usernames, you
need the following in your settings.py::
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_SIGNUP_FIELDS = ['email*', 'password1*', 'password2*']
ACCOUNT_LOGIN_METHODS = {'email'}
Creating and Populating User instances
--------------------------------------
The following adapter methods can be used to intervene in how User
instances are created and populated with data
- ``allauth.account.adapter.DefaultAccountAdapter``:
- ``is_open_for_signup(self, request)``: The default function
returns ``True``. You can override this method by returning ``False``
if you want to disable account signup.
- ``new_user(self, request)``: Instantiates a new, empty ``User``.
- ``save_user(self, request, user, form)``: Populates and saves the
``User`` instance using information provided in the signup form.
- ``populate_username(self, request, user)``:
Fills in a valid username, if required and missing. If the
username is already present, then it is assumed to be valid (unique).
- ``confirm_email(self, request, email_address)``: Marks the email address as
confirmed and saves to the db.
- ``generate_unique_username(self, txts, regex=None)``: Returns a unique username
from the combination of strings present in txts iterable. A regex pattern
can be passed to the method to make sure the generated username matches it.
Invitations
-----------
Invitation handling is not supported, and most likely will not be any
time soon. An invitation app could cover anything ranging from
invitations of new users, to invitations of existing users to
participate in restricted parts of the site. All in all, the scope of
invitation handling is large enough to warrant being addressed in an
app of its own.
Still, everything is in place to easily hook up any third party
invitation app. The account adapter
(``allauth.account.adapter.DefaultAccountAdapter``) offers the following
methods:
- ``is_open_for_signup(self, request)``. You can override this method to, for
example, inspect the session to check if an invitation was accepted.
- ``stash_verified_email(self, request, email)``. If an invitation was
accepted by following a link in an email, then there is no need to
send email verification mails after the signup is completed. Use
this method to record the fact that an email address was verified.
Custom Redirects
----------------
If redirecting to statically configurable URLs (as specified in your
project settings) is not flexible enough, then you can override the
following adapter methods:
- ``allauth.account.adapter.DefaultAccountAdapter``:
- ``get_login_redirect_url(self, request)``
- ``get_logout_redirect_url(self, request)``
- ``get_email_verification_redirect_url(self, email_address)``
- ``get_signup_redirect_url(self, request)``
For example, redirecting to ``/accounts//`` can be implemented as
follows::
# project/settings.py:
ACCOUNT_ADAPTER = 'project.users.adapter.MyAccountAdapter'
# project/users/adapter.py:
from django.conf import settings
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
path = "/accounts/{username}/"
return path.format(username=request.user.username)