Authentication
The authentication module provides plugins to establish the identity of end-users filling out a form. They implement the actual login flow for end-users at the beginning of a form submission.
Identifying attributes can then be used by Prefill to retrieve additional details of the citizen or company. Depending on the authentication plugin used, a certain level of assurance regarding the authentication strength can be obtained as well, increasing trust for higher levels.
In the form builder, it’s possible to specify which plugins are available for authentication. Some plugins allow additional form-specific configuration.
Python API
Module interface
The module-level API serves as an abstraction over the various plugins.
- class openforms.authentication.service.AuthAttribute(*values)
core identifying attributes retrieved from the authentication plugins
- class openforms.authentication.service.BaseAuth
The base structure of authentication data.
- plugin: str
The unique identifier of the plugin that inititiated the authentication data.
- openforms.authentication.service.check_user_is_submission_initiator(request: HttpRequest, submission: Submission) bool
Test if the logged in user matches the user who started the submission.
The logged in user is not to be confused with a Django user, but the user stored in the session under
FORM_AUTH_SESSION_KEYafter logging in for a particular form.The session details are compared against
submission.auth_info. A match happens when the same auth plugin and identifier are present on both.Callers must verify that:
Returns
Trueif there’s a match, andFalseotherwise.
Plugin interface
Authentication plugins must inherit from the base plugin.
Plugins that use the OpenID Connect (OIDC) protocol should inherit from the OIDC plugin
base openforms.contrib.auth_oidc.plugin.OIDCAuthentication.
Plugin base API
- class openforms.authentication.base.BasePlugin(identifier: str)
- auth_info_to_auth_context(auth_info: AuthInfo) AnyAuthContext
Plugin custom auth info to auth context handling.
This will be executed during the AuthInfo
to_auth_context_datawhenmanage_auth_contextis set toTrue.
- check_requirements(request: AnyRequest, options: OptionsT) bool
Check if the request meets requirements
- configuration_options: SerializerCls | None = None
A serializer class describing the plugin-specific configuration options.
A plugin instance is the combination of a plugin callback and a set of options that are plugin specific. Multiple forms can use the same plugin with different configuration options. Using a serializer allows us to serialize the options as JSON in the database, and de-serialize them into native Python/Django objects when the plugin is called.
- handle_co_sign(request: HttpRequest, form: Form) CosignSlice
Process the authentication and return a dict of co-sign details.
The co-sign details are stored on
Submission.co_sign_dataand must match the schema (except for thepluginkey).
- logout(request: HttpRequest)
Can be overridden to implement custom logout behaviour
- class openforms.authentication.base.Choice
- class openforms.authentication.base.CosignSlice
- class openforms.authentication.base.LoginInfo(identifier: str, label: StrOrPromise, logo: openforms.authentication.base.LoginLogo | None = None, url: str | None = None, is_for_gemachtigde: bool = False, visible: bool = True)
- class openforms.authentication.base.LoginLogo(title: StrOrPromise, image_src: str, appearance: str, href: str = '')
- class openforms.authentication.base.Options
Plugin Generic OIDC class
- class openforms.contrib.auth_oidc.plugin.OIDCAuthentication(identifier: str)
- get_error_message_parameters(error: str, error_description: str) tuple[str, str]
Return the message code and the error description for a failed login.
- handle_co_sign(request: HttpRequest, form: Form) CosignSlice
Process the authentication and return a dict of co-sign details.
The co-sign details are stored on
Submission.co_sign_dataand must match the schema (except for thepluginkey).
- handle_return(request: HttpRequest, form: Form, options: OptionsT)
Redirect to form URL.
- logout(request: HttpRequest)
Can be overridden to implement custom logout behaviour
- verbose_name: StrOrPromise = ''
Specify the human-readable label for the plugin.
Available implementations
The following plugins are available in Open Forms core.
Demo, DigiD Mock, Outage
Demo plugins, available only to admin users and when demo plugins are enabled in the configuration. They allow simulating various login mechanisms without requiring a real integration.
DigiD
Provides DigiD integration via the SAMLv2 standards. Implemented using the library django-digid-eherkenning.
eHerkenning and eIDAS
Provides eHerkenning and eIDAS integration via the SAMLv2 standards. Implemented through the library django-digid-eherkenning.
DigiD and eHerkenning/eIDAS via OpenID Connect
DigiD, eHerkenning and eIDAS support through the OIDC protocol rather than SAML. Depends
on an OpenID Connect provider that implements the SAML flows under the hood. Implemented
using the oidc flavour of the django-digid-eherkenning library.
Organisation (OIDC)
Provides authentication for staff users through their organisation single-sign on. Shares the OpenID Connect configuration for the admin login option, but is exposed to form authentication as well.
Yivi (OIDC)
Yivi authenticates based on attributes (which could be a bsn or kvk-number) disclosed by the end users. As a consequence, we cannot know beforehand which specific claims will be received after authentication.
Configuration is done in the admin via Configuratie > OIDC Clients and then yivi-oidc.
Note
End-users must have the Yivi app installed on their phone.
Warning
Due to technical reasons, Yivi support is currently only available through Signicat.
Form specific configuration
When configuring the Yivi plugin, in the form builder, you can specify which
authentication options are available during login (bsn, kvk and/or pseudo) and which
additional attributes should be requested from the user. See
openforms.authentication.contrib.yivi_oidc.config.YiviOptionsSerializer for
details.
Requesting attributes using the condiscon system
Condiscon is a Yivi-specific way of defining the authentication attributes to request from users. With condiscon you define a multi-layer conditional data structure, which provides users more control over which attributes they do and don’t provide.
openforms.authentication.contrib.yivi_oidc.config.YiviOptionsSerializer.authentication_options
and openforms.authentication.contrib.yivi_oidc.config.YiviOptionsSerializer.additional_attributes_groups
determine which attributes to include in the condiscon parameter.
openforms.authentication.contrib.yivi_oidc.oidc_plugins.YiviPlugin.get_extra_params() retrieves the
authentication backend options and adds the attributes to the authentication request.
As the condiscon scope is form-specific, we need to modify the authentication request scopes dynamically. The scope is shaped following the Signicat parameters scope standard.
Note
Important notes about the Yivi attributes and condiscon!
For the Yivi authentication to be successful, at least one attribute needs to be disclosed.
The order of optional disjunction matters. Make sure that the “empty” option is the last item in the disjunction list.
Example of a valid optional disjunction:
[ [ ["pbdf.pbdf.diploma.degree"], [], ] ]
Authentication result
Which authentication value (bsn, kvk or pseudo) is returned by the plugin depends on the form-specific configuration, and the data provided by the user.
To determine which authentication option was used you have to check the returned claims.
This is done by the _get_user_chosen_authentication_attribute() function; it
checks the returned claims against the configuration for bsn and kvk claims. If
they match, then we know if the user logged in using bsn, kvk or anonymous/pseudo.
Generic OIDC support
The current Yivi setup is limited to Signicat condiscon. For generic OIDC support we need to investigate how other identity providers work with Yivi.
In this context, “generic OIDC” means the normal way of working with OIDC, similar to how DigiD and eHerkenning via OIDC work. Instead of one gigantic bundled scope, you provide individual scopes for the claims you want to be fulfilled.
(This way of working might result into losing the major strength of Yivi; that the user can choose what data they provide.)
Generic OIDC authentication with Signicat
One piece of the puzzle: generic OIDC authentication via Signicat.
Besides the condiscon scope, Signicat also supports generic OIDC authentication. With the generic OIDC authentication you don’t provide a single scope that results in multiple claims; rather, you pass each Yivi attribute as an individual scope item.
For example, the following scope will request the bsn and fullname of a user:
scope: "openid irma-demo.gemeente.personalData.bsn irma-demo.gemeente.personalData.fullname"
Whether other identity providers work similarly is yet to determine.
Reference
Plugin for Yivi authentication
Website: https://yivi.nl/
For development, we can use the Yivi demo attribute sets: https://attribute-index.yivi.app/en/irma-demo.html.
See the project documentation for more information about Yivi authentication.
- class openforms.authentication.contrib.yivi_oidc.config.YiviOptionsSerializer(*args, **kwargs)
- class openforms.authentication.contrib.yivi_oidc.plugin.YiviOIDCAuthentication(identifier: str)
- auth_info_to_auth_context(auth_info: AuthInfo) YiviContext
Plugin custom auth info to auth context handling.
This will be executed during the AuthInfo
to_auth_context_datawhenmanage_auth_contextis set toTrue.
- check_requirements(request: AnyRequest, options: YiviOptions) bool
Check if the request meets requirements
- configuration_options
alias of
YiviOptionsSerializer
- verbose_name: StrOrPromise = 'Yivi via OpenID Connect'
Specify the human-readable label for the plugin.
- class openforms.authentication.contrib.yivi_oidc.oidc_plugins.plugins.YiviPlugin(identifier: str)
- get_extra_params(request: HttpRequest, extra_params: GetParams) GetParams
Return (additional)
GETparameters for the redirect to the identity provider.By default, the passed in
extra_paramsare returned unmodified.- Parameters:
extra_params – A mapping of query parameters already produced by
mozilla_django_oidc_db.views.OIDCAuthenticationRequestInitView.
- get_or_create_user(access_token: str, id_token: str, payload: JSONObject, request: HttpRequest) AnonymousUser
Return a “fake” Django user.
If the claims are valid, we only process them and do not create or update an actual Django user.
- 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
optionsJSONField of theOIDCClientmodel.The admin integration needs a JSON Schema definitions to be able to configure and validate the options when editing the client configuration.
- handle_callback(request: HttpRequest) HttpResponseBase
Return an HttpResponse using a specific callback view.
Typed as
HttpResponseBasebecause that’s the annotation forView.as_view()in django-stubs.For example:
def handle_callback(self, request: HttpRequest) -> HttpResponseBase: return admin_callback_view(request)
- validate_settings() None
Check the validity of the settings in the provider and client configuration.
- Raises:
ImproperlyConfigured – if invalid configuration is detected.