Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 139 additions & 28 deletions docs/configuration/django.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,34 @@ working in your Django project.
'social_django',
)

**2. Configure authentication backends** (example for Google OAuth2)::
**2. Add the exception middleware**:

Add ``SocialAuthExceptionMiddleware`` to your existing ``MIDDLEWARE`` list,
after the session, authentication, and message middleware::

MIDDLEWARE = [
...
'social_django.middleware.SocialAuthExceptionMiddleware',
]

This is recommended so expected authentication failures, such as an expired
login session or declined authorization, show a useful error page instead of
an HTTP 500 response. No error URL is required; configure
``SOCIAL_AUTH_LOGIN_ERROR_URL`` if you prefer a redirect to your own error page.
See :ref:`django-exception-middleware` for customization and reporting behavior.

With ``DEBUG = True``, exceptions propagate by default to aid debugging. Set
``SOCIAL_AUTH_RAISE_EXCEPTIONS = False`` to preview the error page during local
development.

**3. Configure authentication backends** (example for Google OAuth2)::

AUTHENTICATION_BACKENDS = (
'social_core.backends.google.GoogleOAuth2',
'django.contrib.auth.backends.ModelBackend', # Keep for username/password login
)

**3. Add OAuth credentials to settings.py**:
**4. Add OAuth credentials to settings.py**:

This is where you configure your ``client_id``, ``client_secret``, and ``scope`` for each provider::

Expand All @@ -64,20 +84,20 @@ For other providers, the pattern is ``SOCIAL_AUTH_<PROVIDER>_KEY``,
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get('GOOGLE_OAUTH2_KEY')
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get('GOOGLE_OAUTH2_SECRET')

**4. Add URLs to urls.py**::
**5. Add URLs to urls.py**::

urlpatterns = [
...
path('', include('social_django.urls', namespace='social')),
]

**5. Configure redirect URLs**::
**6. Configure redirect URLs**::

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

**6. Run migrations**::
**7. Run migrations**::

python manage.py migrate

Expand All @@ -87,7 +107,7 @@ command. The Django migration adds a blank ``id_key`` to existing social
associations; social-core then migrates those rows according to the policy in
:ref:`the configurable user ID key documentation <configurable-user-id-key>`.

**7. Add login form in template**::
**8. Add login form in template**::

<form method="post" action="{% url 'social:begin' 'google-oauth2' %}">
{% csrf_token %}
Expand Down Expand Up @@ -398,30 +418,118 @@ compatibility. The historical ``SOCIAL_AUTH_JSONFIELD_ENABLED``,
settings are only relevant while running those legacy migrations.


.. _django-exception-middleware:

Exceptions Middleware
---------------------

A base middleware is provided that handles ``SocialAuthBaseException`` by
providing an error message to the user via configured transport mechanisms (Django
messages framework, redirect URL query parameters, or both), and then
responding with a redirect to a URL defined in one of the middleware methods.
A base middleware handles ``SocialAuthBaseException`` by redirecting to a
configured error URL or rendering an error page. It supports both synchronous
and asynchronous Django request handlers. Add it to ``MIDDLEWARE``, after your
session, authentication, and message middleware:

The middleware is at ``social_django.middleware.SocialAuthExceptionMiddleware``.
Any method can be overridden, but for simplicity these two are recommended:
.. code-block:: python

MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'social_django.middleware.SocialAuthExceptionMiddleware',
]

To redirect failures to an application error page, configure:

.. code-block:: python

get_message(request, exception)
get_redirect_uri(request, exception)
SOCIAL_AUTH_LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_RAISE_EXCEPTIONS = False

The redirect uses the configured error transports described below. The default
message is the safe exception message. A backend attached by the ``psa()``
decorator is available at ``request.backend``; backend-specific settings take
precedence over global settings.

Without this middleware, Social Auth exceptions are left to Django's exception
handling and can produce an HTTP 500 response.

Fallback error page
^^^^^^^^^^^^^^^^^^^

When ``SOCIAL_AUTH_LOGIN_ERROR_URL`` is unset, ``None``, or an empty string, the
middleware renders ``social_django/error.html`` directly. It does not use flash
messages or query parameters, so the page works even when session cookies are
unavailable. Explicit exception propagation still takes precedence, as described
under exception raising below.

The response status depends on the failure:

.. list-table::
:header-rows: 1

* - Exception family or reason
- HTTP status
* - ``AuthInputError``
- 400
* - ``AuthSessionError``, ``AuthCredentialError``, ``AuthPolicyError``, ``AuthCanceled``
- 403
* - ``AuthAssociationError``
- 409
* - ``AuthResponseError``
- 502
* - ``AuthProviderError``: connection, unavailability, rate limit, or custom codes
- 503
* - ``AuthProviderError``: ``timeout``
- 504
* - ``AuthProviderError``: ``tls_error`` or ``http_error``
- 502
* - Configuration errors, unknown errors, or other base exceptions
- 500

The reason codes ``response_expired`` and ``nonce_mismatch`` override the family
status with 403; ``invalid_expiry`` overrides it with 500. Other custom codes
inherit the family's status. Provider HTTP statuses are not forwarded directly.

The bundled page shows the safe message and guidance selected from the suggested
recovery action. Only ``session_context_missing`` adds a hint about session expiry,
cookies, and restarting login in the same browser and container. These are possible
causes, not a diagnosis. The page does not automatically retry authentication.

Override ``social_django/error.html`` in your application's templates to customize
its presentation. The middleware supplies ``message``, ``error_code``,
``error_source``, ``error_stage``, and ``error_recovery``; it does not supply the raw
exception, provider diagnostics, or identifying context. Normal Django template
context processors still apply. The response includes headers preventing caching.

You can also subclass the middleware and replace its ``MIDDLEWARE`` entry with
your subclass. The following methods accept ``request`` and ``exception``:

* ``get_message()`` customizes the message for redirects and rendered pages.
* ``get_redirect_uri()`` selects the error redirect URL.
* ``get_error_status()`` selects the rendered response's HTTP status.
* ``render_error()`` customizes the rendered response and its reporting.

For example, an application can change the status used for explicit cancellation:

By default, the message is the exception message and the URL for the redirect
is the location specified by the ``LOGIN_ERROR_URL`` setting. The middleware
supports both synchronous and asynchronous Django request handlers.
.. code-block:: python

from social_core.exceptions import AuthCanceled
from social_django.middleware import SocialAuthExceptionMiddleware

If a valid backend was detected by ``strategy()`` decorator, it will be
available at ``request.strategy.backend`` and ``process_exception()`` will
use it to build a backend-dependent redirect URL but fallback to default if not
defined.
class CustomExceptionMiddleware(SocialAuthExceptionMiddleware):
def get_error_status(self, request, exception):
if isinstance(exception, AuthCanceled):
return 400
return super().get_error_status(request, exception)

Rendered 4xx failures are logged at warning level using safe classification
fields, without tracebacks. Rendered 5xx failures are logged at error level with
the original exception and traceback so server-side defects remain diagnosable.
Tracebacks are included only in server logs, not in the rendered page.
Rendering a 500 handles the exception instead of propagating it, so
exception-based monitoring may no longer receive it. Configure monitoring for
the logs or override ``render_error()`` to integrate your reporting. Unrelated
exceptions still propagate through Django normally.

Error Transports
^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -571,15 +679,18 @@ different authentication providers, such as showing a custom error page for cert
providers or raising exceptions for debugging specific backends while keeping
others in production mode.

Exception processing is disabled if any of these settings is defined with a
``True`` value:
Exception processing is disabled when the effective ``RAISE_EXCEPTIONS``
setting is true. Settings are checked in this order, and the first configured
value wins:

.. code-block:: python
1. ``SOCIAL_AUTH_<BACKEND>_RAISE_EXCEPTIONS`` (uppercase backend name, with
hyphens replaced by underscores).
2. ``SOCIAL_AUTH_RAISE_EXCEPTIONS``.
3. ``RAISE_EXCEPTIONS``.
4. ``DEBUG`` as the default when none of these settings is configured.

<backend name>_SOCIAL_AUTH_RAISE_EXCEPTIONS = True
SOCIAL_AUTH_RAISE_EXCEPTIONS = True
RAISE_EXCEPTIONS = True
DEBUG = True
For example, ``SOCIAL_AUTH_RAISE_EXCEPTIONS = False`` enables handling even with
``DEBUG = True``; a backend-specific true value overrides that global false value.


Structured authentication errors
Expand Down
10 changes: 8 additions & 2 deletions docs/configuration/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,16 @@ results and others for error situations.
value of the ``next`` request parameter is used if it was present

``SOCIAL_AUTH_LOGIN_ERROR_URL = '/login-error/'``
URL where the user will be redirected in case of an error
URL where the user will be redirected in case of an error. With Django's
``SocialAuthExceptionMiddleware``, leaving this unset or empty renders the
bundled error page instead. See :doc:`django` for status mappings and
customization. The Django exception middleware does not fall back to
``SOCIAL_AUTH_LOGIN_URL``.

``SOCIAL_AUTH_LOGIN_URL = '/login-url/'``
Is used as a fallback for ``LOGIN_ERROR_URL``
Fallback login URL used by authentication actions when a more specific
redirect URL is unavailable. It is not a fallback for Django's exception
middleware.

``SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/new-users-redirect-url/'``
Used to redirect new registered users, will be used in place of
Expand Down
Loading