This package adds OpenID Connect authentication functionality for Django projects.
- Autoconfiguration via the
/.well-known/openid-configurationendpoint - Support for refresh tokens
- The session duration is limited by the expiration time of the refresh token
- The authentication middleware that the user always has a valid access token and refreshes it when it has expired
- SSO sessions:
- Checking for an active SSO session using a redirection to the authentication endpoint with
prompt=none - Endpoint for ending the SSO session and logging out from Django
- (Planned) Back-channel logout
- Checking for an active SSO session using a redirection to the authentication endpoint with
- Support for disabling the
OidcAuthBackendin the settings file without requiring other changes to the views - Syncing of user groups and staff/superuser status based on the
realm_access.rolesclaim in the access token - Custom
@ksi_oidc_login_requiredand@ksi_oidc_check_ssoview decorators - Automatic client configuration using the OpenID Connect Dynamic Client Registration protocol
The source code of this library incorporates modified source code from the mozilla-django-oidc library. The fragments based on mozilla-django-oidc are appropriately marked in comments in the source code. mozilla-django-oidc is licenced under the Mozilla Public License 2.0, available here.
In the appropriate Django setting files:
-
Add
django.contrib.auth(if not yet added) andksi_oidc_djangotoINSTALLED_APPS.It is required for adding the models for this library when running
manage.py migrateand provides extra configuration checks.INSTALLED_APPS = [ # ... 'django.contrib.auth', # ... 'ksi_oidc_django', # ... ]
-
Add the
OidcAuthMiddlewaretoMIDDLEWARE:It must be placed directly after Django's
AuthenticationMiddleware, because it is required for the session expiry and refresh logic to work. If any other middleware was added in betweenAuthenticationMiddlewareandOidcAuthMiddleware, therequest.usermight be a user whose session has expired while processing that middleware.See the Middleware Ordering section in the Django docs for a standard order of other middleware.
MIDDLEWARE = [ # ... 'django.contrib.sessions.middleware.SessionMiddleware', # ... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'ksi_oidc_django.middleware.OidcAuthMiddleware', # ... ]
-
Add
ksi_oidc_django-specific settings:OIDC_APP_BASE_URL = 'https://yourapp.com/' # Set user's Django groups to the roles from the access token claims. # Roles from the `realm_access.roles` claim will be saved as groups with the names `oidc.realm.{group_name}`. # Roles from the `resource_access.{client_id}.roles` claim will be saved as `oidc.client.{group_name}`. # If the user is in any other group with a name starting with `oidc.`, it will be removed. # See https://www.keycloak.org/docs/latest/server_admin/index.html#_oidc_token_role_mappings for more details. OIDC_SYNC_ROLES_AS_GROUPS = True # Sets or unsets the User.is_staff and User.is_superuser fields # if the user's `realm_access.roles` or `resource_access.${client_id}.roles` claims contain the specified role. # The settings are tuples in the form `('realm', role_name)` or `('client', role_name)`. # Set to None to disable this feature. # See https://www.keycloak.org/docs/latest/server_admin/index.html#_oidc_token_role_mappings for more details. OIDC_STAFF_ROLE = ('client', 'my-app-staff') OIDC_SUPERUSER_ROLE = ('client', 'my-app-superuser') OIDC_SSO_CHECK_COOLDOWN_SECONDS = 300
-
Add
OidcAuthBackendtoAUTHENTICATION_BACKENDS:AUTHENTICATION_BACKENDS = ( # This is the standard Django backend, you can remove it if you only use # OpenID Connect for authentication. 'django.contrib.auth.backends.ModelBackend', 'ksi_oidc_django.backends.OidcAuthBackend', )
You can disable the
OidcAuthBackendwithout removing the app and middleware. The middleware will detect that the backend is not enabled and raiseMiddlewareNotUsed. -
Use the
manage.py oidc_set_issuerandmanage.py oidc_init_dynamic/manage.py oidc_init_staticcommands to configure the OpenID Connect client.
Add these entries in your urls.py:
urlpatterns = [
# ...
path('login/', OidcLoginView.as_view(), name='login'),
# Register the endpoints `/oidc/callback/` and `/oidc/logout/`:
path('oidc/', include('ksi_oidc_django.urls')),
]You may change the paths. Make sure to set the setting LOGIN_URL to the path of the login page.
ksi-oidc-django also uses the standard LOGOUT_REDIRECT_URL setting, set it to the path
you want the user to be redirected to after logging out.
In the settings of your OIDC provider you will need to add the /oidc/callback/ URL as a valid redirect URL
and the LOGOUT_REDIRECT_URL URL as a valid post logout redirect URL.
OidcLoginView redirects the user to the OIDC provider's login page if the OidcAuthBackend is enabled.
If it's not, it uses the view specified in OidcLoginView.fallback_view to render the login page.
It uses DjangoLoginView by default. You can use a different view for this by specifying the fallback_view
when calling .as_view():
urlpatterns = [
# ...
path('login/', OidcLoginView.as_view(fallback_view=MyFallbackLoginView.as_view()), name='login'),
# ...
]ksi-oidc-django provides these new view decorators:
-
@ksi_oidc_login_requiredperforms the same check as Django's@login_required, but if the user is not logged in, it redirects the user directly to the OIDC login page (if theOidcAuthBackendis enabled).If you were to use
@login_requiredinstead, accessing a protected view would redirect the user twice, first to theLOGIN_URL, which would then redirect the user to the OIDC login page. -
@ksi_oidc_check_ssois used for views that do not require authentication. When an unauthenticated user tries to access a view decorated with@ksi_oidc_check_sso, they will be redirected to the OIDC authentication endpoint withprompt=none, to check if the user already has an active SSO session.The
OIDC_SSO_CHECK_COOLDOWN_SECONDSsetting controls the minimum time between such checks.
The publicly accessible base URL of your application, including the protocol and port,
for example https://yourapp.com/.
Set user's Django groups to the roles from the access token claims:
- Roles from the
realm_access.rolesclaim will be saved as groups with the namesoidc.realm.{group_name}. - Roles from the
resource_access.{client_id}.rolesclaim, where{client_id}is the Client ID configured for this plugin, will be saved asoidc.client.{group_name}. - If the user is in any other group with a name starting with
oidc., it will be removed.
See https://www.keycloak.org/docs/latest/server_admin/index.html#_oidc_token_role_mappings for more details.
Set or unset the User.is_staff and User.is_superuser fields
if the user's realm_access.roles or resource_access.${client_id}.roles claims contain the specified role.
The settings are tuples in the form ('realm', role_name) or ('client', role_name).
Set to None to disable this feature.
See https://www.keycloak.org/docs/latest/server_admin/index.html#_oidc_token_role_mappings for more details.
The time after a redirect to the OIDC authentication endpoint with prompt=none
when using the @ksi_oidc_check_sso decorator during which the user will not be redirected again.
If unspecified, the default value is 300 - 5 minutes.