Reference

Public API documentation.

Views

class mozilla_django_oidc_db.views.AdminCallbackView(**kwargs)

Intercept errors raised by the authentication backend and display them.

get(request: HttpRequest, *args, **kwargs)

Callback handler for OIDC authorization code flow

class mozilla_django_oidc_db.views.AdminLoginFailure(**kwargs)

Template view in admin style to display OIDC login errors

class mozilla_django_oidc_db.views.OIDCAuthenticationCallbackView(**kwargs)

Base callback view that retrieves the settings from the config object.

get_settings(attr: str, *args: Any) Any

Look up the request setting from the database config.

For the duration of the request, the configuration instance is cached on the view.

class mozilla_django_oidc_db.views.OIDCAuthenticationRequestInitView(*args, **kwargs)

A ‘view’ to start an OIDC authentication flow.

This view class is parametrized with the identifier of the config model, so that the specific configuration can be retrieved and settings such as the identity provider endpoint to redirect the user to can be obtained.

This view is not necessarily meant to be exposed directly via a URL pattern, but rather specific views are to be created from it, e.g.:

>>> digid_init = OIDCAuthenticationRequestInitView.as_view(identifier="digid-oidc")
>>> redirect_response = digid_init(request)
# Redirect to some keycloak instance, for example.

The __init__ method of the Django View will add attributes to the view for any args/kwargs passed during init. So the view will have an attribute identifier. Note that it only does it for attributes that are already defined as class attributes.

These concrete views are intended to be wrapped by your own views so that you can supply the return_url parameter:

def my_digid_login(request):
    return digid_init(request, return_url=request.GET["next"])

Compared to mozilla_django_oidc.views.OIDCAuthenticationRequestView, some extra actions are performed:

  • Any Keycloak IdP hint is added, if configured

  • The return_url is validated against unsafe redirects

  • The availability of the identity provider endpoint can be checked, if it’s not available, the mozilla_django_oidc_db.exceptions.OIDCProviderOutage exception is raised. Note that your own code needs to handle this appropriately!

allow_next_from_query: bool = True

Specify if the url-to-redirect-to may be provided as a query string parameter.

For OIDC auth in the admin, you want to enable this to make URLs like /oidc/authenticate/?next=/admin/ work as expected. For more advanced flows, you may want explicit control over this URL via your own wrapper view:

digid_init = OIDCAuthenticationRequestInitView.as_view(
    identifier="config-identifier", allow_next_from_query=False
)

def my_digid_login(request):
    return digid_init(request, return_url="/some-fixed-url")
check_idp_availability() None

Hook for subclasses.

Raise OIDCProviderOutage if the Identity Provider is not available, which your application code needs to handle.

The default implementation checks if the endpoint has a status code < 401.

get(request: HttpRequest, return_url: str = '', *args, **kwargs) HttpResponseRedirect

OIDC client authentication initialization HTTP endpoint

get_extra_params(request: HttpRequest) GetParams

Add a keycloak identity provider hint if configured.

get_settings(attr: str, *args: Any) Any

Look up the requested setting from the plugin, which defers to the DB config.

For the duration of the request, the plugin instance is cached on the view.

identifier: str = ''

The identifier of the config model to get the settings from.

Specify this as a kwarg in the as_view(identifier=...) class method.

class mozilla_django_oidc_db.views.OIDCAuthenticationRequestView(*args, **kwargs)

Start an OIDC authentication flow.

This view is pre-configured to use the OIDC configuration included in this library, intended for admin authentication. Enable it in your Django settings with:

OIDC_AUTHENTICATE_CLASS = (
    "mozilla_django_oidc_db.views.OIDCAuthenticationRequestView"
)
allow_next_from_query: bool = True

Specify if the url-to-redirect-to may be provided as a query string parameter.

For OIDC auth in the admin, you want to enable this to make URLs like /oidc/authenticate/?next=/admin/ work as expected. For more advanced flows, you may want explicit control over this URL via your own wrapper view:

digid_init = OIDCAuthenticationRequestInitView.as_view(
    identifier="config-identifier", allow_next_from_query=False
)

def my_digid_login(request):
    return digid_init(request, return_url="/some-fixed-url")
identifier: str = 'admin-oidc'

The identifier of the config model to get the settings from.

Specify this as a kwarg in the as_view(identifier=...) class method.

class mozilla_django_oidc_db.views.OIDCCallbackView(**kwargs)

Route to the appropriate callback request handler.

When a callback request is received, the state contains information about the configuration model to use. A particular configuration may require certain view behaviour. This view acts as a centralized entrypoint so that there is only a single callback endpoint required. It ensures that the configuration is extracted from the request.

get(request: HttpRequest, *args, **kwargs) HttpResponseBase

Extract the state from the request parameters and persist it.

The state is extracted so that it’s available for the authentication backend(s) and the downstream views.

mozilla_django_oidc_db.views.admin_callback_view(request, *args, **kwargs)

Intercept errors raised by the authentication backend and display them.

mozilla_django_oidc_db.views.default_callback_view(request, *args, **kwargs)

Base callback view that retrieves the settings from the config object.

Authentication backends

class mozilla_django_oidc_db.backends.OIDCAuthenticationBackend(*args, **kwargs)

Custom backend modifying the upstream package behaviour.

This backend looks up the configuration to use, which is set on the request by the init view. It does this by grabbing the state query parameter and looking in the session for this key. This key was set by the authentication request view. Scoped inside the state, there is the identifier of the configuration to use.

The authenticate method saves the request on the backend instance.

No configuration is loaded in __init__() at all, instead we define properties to dynamically look this up. Django instantiates backends a lot, e.g. during permission checks. We only support the authenticate() entrypoint like the upstream library.

authenticate(request: HttpRequest | None, nonce: str | None = None, code_verifier: str | None = None) AnonymousUser | AbstractBaseUser | None

Authenticate the user with OIDC iff the conditions are met.

Return None to skip to the next backend, raise django.core.exceptions.PermissionDenied to stop in our tracks. Return a user object (real or anonymous) to signify success.

create_user(claims: JSONObject) AbstractUser

Create an authenticated user.

filter_users_by_claims(claims: JSONObject) QuerySet

Return all users matching the specified email.

get_or_create_user(access_token: str, id_token: str, payload: JSONObject) AnonymousUser | AbstractUser | None

Get or create a user based on the tokens received.

get_settings(attr: str, *args: Any) Any

Override the upstream library get_settings.

Upstream is django-settings based, and we store configuration in database records instead. We look up the configuration from the DB and check if the requested setting is defined there or not. If not, it is taken from the Django settings.

get_userinfo(access_token: str, id_token: str, payload: JSONObject) JSONObject

Extract the user information, configurable whether to use the ID token or the userinfo endpoint for this

update_user(user: AbstractUser, claims: JSONObject)

Update existing user with new claims, if necessary save, and return user

verify_claims(claims: JSONObject) bool

Verify the provided claims to decide if authentication should be allowed.

Models

class mozilla_django_oidc_db.models.OIDCClient(*args, **kwargs)

Hold the client configuration for the Relying Party (RP).

At minimum, the client credentials need to be configured for the associated OIDC Provider (OP). Additional dynamic configuration options can be specified that are tied to specific use cases.

exception DoesNotExist
exception MultipleObjectsReturned
exception NotUpdated
property oidc_rp_scopes: str

Scopes should be formatted as a string with spaces

class mozilla_django_oidc_db.models.OIDCProvider(*args, **kwargs)

Manage the configuration/connection parameters for a single OIDC Provider (OP).

exception DoesNotExist
exception MultipleObjectsReturned
exception NotUpdated
class mozilla_django_oidc_db.models.UserInformationClaimsSources(*values)
mozilla_django_oidc_db.models.get_default_scopes() list[str]

Returns the default scopes to request for OpenID Connect logins

class mozilla_django_oidc_db.fields.ClaimField(*args, **kwargs)

A field to store a path to claims holding the desired value(s).

Each item is a segment in the path from the root to leaf for nested claims.

class mozilla_django_oidc_db.fields.ClaimFieldDefault(*args, **kwargs)

Callable default for ClaimField.

Django’s ArrayField requires a callable to be passed for the default kwarg, to avoid sharing a mutable value shared by all instances. This custom class provides a straight-forward interface so that defaults can be provided inline rather than requiring a function to be defined at the module level, since lambda’s cannot be serialized for migrations.

Usage:

>>> field = ClaimField(default=ClaimFieldDefault("foo", "bar"))
>>> field.get_default()  # ["foo", "bar"]
deconstruct()

Return a 3-tuple of class import path, positional arguments, and keyword arguments.

Utils

mozilla_django_oidc_db.utils.do_op_logout(config: OIDCClient, id_token: str) None

Perform the logout with the OpenID Provider.

Standard: https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout

Warning

Preferably, you should send the user to the configured logout endpoint so they can confirm the logout and any session cookies are cleared. If that is not possible, you can call this helper for server-to-server logout, but there are no guarantees this works for every possible OpenID Provider implementation. It has been tested with Keycloak, but the standard says nothing about server-to-server calls to log out a user.

mozilla_django_oidc_db.utils.get_groups_by_name(group_names: Iterable[str], sync_groups_glob: str, sync_missing_groups: bool) set[Group]

Gets Django User groups by name.

Optionally creates missing groups that match glob pattern.

mozilla_django_oidc_db.utils.obfuscate_claims(claims: JSONObject, claims_to_obfuscate: Collection[ClaimPath]) JSONObject

Obfuscates the specified claims in the provided claims object.

Signals

mozilla_django_oidc_db.signals.populate_oidc_config_models(sender, **kwargs) None

See which OIDC plugins are registered and make sure that the corresponding configuration model exists in the database.

mozilla_django_oidc_db.signals.set_oidcdb_config_identifier_on_session(sender, user, request, **kwargs)

Record the OIDC config identifier on the session, this is needed so the callback view can retrieve the config in case of a SessionRefresh flow.

Plugins

class mozilla_django_oidc_db.plugins.AbstractUserOIDCPlugin(identifier: str)
class mozilla_django_oidc_db.plugins.AnonymousUserOIDCPlugin(identifier: str)
class mozilla_django_oidc_db.plugins.BaseOIDCPlugin(identifier: str)

Base class/interface for all plugins to implement.

get_config() OIDCClient

Resolve the instance holding the configuration options.

get_extra_params(request: HttpRequest, extra_params: GetParams) GetParams

Return (additional) GET parameters for the redirect to the identity provider.

By default, the passed in extra_params are returned unmodified.

Parameters:

extra_params – A mapping of query parameters already produced by mozilla_django_oidc_db.views.OIDCAuthenticationRequestInitView.

abstractmethod get_schema() JSONObject

Return the JSON Schema definition for the client configuration options.

Each plugin provides certain behaviour that may have configuration parameters. The configuration parameters are stored in the options JSONField of the OIDCClient model.

The admin integration needs a JSON Schema definitions to be able to configure and validate the options when editing the client configuration.

get_setting(attr: str, *args) Any

Look up a particular configuration parameter for the configuration options.

Parameters:
  • attr – The setting/configuration parameter to look up.

  • args – Any additional arguments for the lookup behaviour, typically a default value for missing settings is provided here.

abstractmethod handle_callback(request: HttpRequest) HttpResponseBase

Return an HttpResponse using a specific callback view.

Typed as HttpResponseBase because that’s the annotation for View.as_view() in django-stubs.

For example:

def handle_callback(self, request: HttpRequest) -> HttpResponseBase:
    return admin_callback_view(request)
identifier: str

The unique identifier for the plugin.

Typically provided through the @register(IDENTIFIER) decorator when registering a plugin in downstream code.

abstractmethod validate_settings() None

Check the validity of the settings in the provider and client configuration.

Raises:

ImproperlyConfigured – if invalid configuration is detected.

class mozilla_django_oidc_db.plugins.OIDCAdminPlugin(identifier: str)

Implement the core plugin for admin authentication via OpenID Connect.

create_user(claims: JSONObject) AbstractUser

Return object for a newly created user account.

filter_users_by_claims(claims: JSONObject) QuerySet

Return all users matching the specified subject.

get_schema() JSONObject

Return the JSON Schema definition for the client configuration options.

Each plugin provides certain behaviour that may have configuration parameters. The configuration parameters are stored in the options JSONField of the OIDCClient model.

The admin integration needs a JSON Schema definitions to be able to configure and validate the options when editing the client configuration.

get_username(claims: JSONObject, *, raise_on_empty: bool = False) str

Given the claims, extract the username value.

handle_callback(request: HttpRequest) HttpResponseBase

Return an HttpResponse using a specific callback view.

Typed as HttpResponseBase because that’s the annotation for View.as_view() in django-stubs.

For example:

def handle_callback(self, request: HttpRequest) -> HttpResponseBase:
    return admin_callback_view(request)
update_user(user: AbstractUser, claims: JSONObject) AbstractUser

Update existing user with new claims, if necessary save, and return user.

This method checks dynamic settings, which are provided by our OIDCClient model. If the respective fields do not exist on the config model being used, you must make sure they exist as Django settings.

validate_settings()

Check the validity of the settings in the provider and client configuration.

Raises:

ImproperlyConfigured – if invalid configuration is detected.

verify_claims(claims: JSONObject) bool

Verify the provided claims to decide if authentication should be allowed.

Tests

class mozilla_django_oidc_db.tests.mixins.OIDCMixin

Helpers around mozilla-django-oidc and mozilla-django-oidc-db.

The post-migrate hook populates the pre-defined OIDC clients and providers, which makes the developer experience in (unit) tests worse because you can’t easily update or patch the configurations, since the factories perform a get_or_create rather than update_or_create. We resolve this by removing all records in the test method setup.

It also automatically installs a mock for the random string generation used for the state and nonce values, as these need to be stable to properly work together with VCR request matching.

mozilla_django_oidc_db.tests.mixins.mock_random_state_and_nonce()

Mock the state & nonce random value generation

Needed so that we get predictable URLs to match with VCR.

Keycloak helpers taken from mozilla-django-oidc-db::tests/utils.py & pytest fixtures.

These help dealing with/stubbing out OpenID Provider configuration.

The Keycloak client ID/secret and URLs are set up for the config in docker/docker-compose.keycloak.yml. See the README.md in docker/keycloak/ for more information.

mozilla_django_oidc_db.tests.utils.keycloak_login(login_url: str, username: str = 'testuser', password: str = 'testuser', host: str = 'http://testserver/', session: Session | None = None) str

Test helper to perform a keycloak login.

Parameters:

login_url – A login URL for keycloak with all query string parameters. E.g. client.get(reverse(“login”))[“Location”].

Returns:

The redirect URI to consume in the django application, with the code state query parameters. Consume this with response = client.get(url).