Identity for Django¶
Prerequisite¶
Create a hello world web project in Django.
You can use Django’s own tutorial, part 1 as a reference. What we need are basically these steps:
django-admin startproject mysitepython manage.py migratepython manage.py runserver localhost:5000You must use a port matching your redirect_uri that you registered.Now, add an index view to your project. For now, it can simply return a “hello world” page to any visitor:
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. Everyone can read this line.")
Configuration¶
Install dependency by
pip install identity[django]Create an instance of the
identity.django.Authobject, and assign it to a global variable inside yoursettings.py:import os from dotenv import load_dotenv from identity.django import Auth load_dotenv() AUTH = Auth( # Instruction for these settings is available in this project's README file. # https://github.com/rayluo/identity?tab=readme-ov-file#scenarios-supported os.getenv('CLIENT_ID'), client_credential=os.getenv('CLIENT_SECRET'), redirect_uri= # Recommended to register and use a redirect_uri. # It looks like http://localhost:5000/redirect for local development, # or https://your_website.com/redirect for your production. # If absent, Identity library will fall back to a Device Code mode. os.getenv('REDIRECT_URI'), ..., # See below on how to feed in the authority url parameter )
Tip
We recommend storing settings in environment variables. The snippet above read data from environment variables.
Initializing Auth object differently based on Identity Provider type
Its authority URL looks like
Initialize Auth() object like this
Microsoft Entra ID
https://login.microsoftonline.com/tenantAuth(…, authority=url, …)
Microsoft Entra External ID
https://contoso.ciamlogin.com/contoso.onmicrosoft.comMicrosoft Entra External ID with Custom Domain
https://contoso.com/tenantAuth(…, oidc_authority=url, …)
Azure AD B2C
N/A
Auth(…, b2c_tenant_name=”contoso”, b2c_signup_signin_user_flow=”susi”)
Inside the same
settings.pyfile, add"identity"into theINSTALLED_APPSlist, to enable the default templates came with the identity package:INSTALLED_APPS = [ ..., "identity", ]
Add the built-in views into your
urls.py:from django.conf import settings urlpatterns = [ settings.AUTH.urlpattern, ... ]
Sign In and Sign Out¶
In your web project’s
views.py, decorate some views with theidentity.django.Auth.login_required()decorator:from django.conf import settings @settings.AUTH.login_required def index(request, *, context): user = context['user'] return HttpResponse(f"Hello, {user.get('name')}.")
In your web project’s any template that you see fit, add this URL to present the logout link:
<a href="{% url 'identity.logout' %}">Logout</a>
Web app that logs in users and calls a web API on their behalf¶
Decorate your token-consuming views using the same
identity.django.Auth.login_required()decorator, this time with a parameterscopes=["your_scope_1", "your_scope_2"].Then, inside your view, the token will be readily available via
context['access_token']. For example:@settings.AUTH.login_required(scopes=["your_scope"]) def call_api(request, *, context): api_result = requests.get( # Use access token to call a web api "https://your_api.example.com", headers={'Authorization': 'Bearer ' + context['access_token']}, timeout=30, ).json() # Here we assume the response format is json ...
All of the content above are demonstrated in this django web app sample.
API reference¶
- class identity.django.Auth(*args, post_logout_view: callable | None = None, prompt: str | None = None, **kwargs)¶
A long-live identity auth helper for a Django web project.
Afterwards, all you need to do is to insert
auth.urlpatterninto your project’surlpatternslist inyour_project/urls.py.- __init__(*args, post_logout_view: callable | None = None, prompt: str | None = None, **kwargs)¶
Initialize the Auth class for a Django web application.
- Parameters:
post_logout_view¶ (callable) –
Optional. If not provided, the user will be redirected to the root URL of the app.
If provided, it shall be the view (which is a function) that will be redirected to, after the user has logged out. For example, you will typically use this parameter like this:
from . import public_views # This module shall NOT import settings.AUTH auth = Auth( ..., post_logout_view=public_views.my_post_logout_view, )
where
my_post_logout_viewis a Django view function.prompt¶ (str) –
Optional. The prompt parameter to be used during login. Valid values are defined in OpenID Connect Core spec.
Starting from Identity 0.11.0, the default value is changed from
"select_account"toNone.Nonemeans no prompt will be sent in the authentication request, not even string"none". The Identity Server will decide whether to prompt.
- get_edit_profile_url()¶
A helper to get the URL for Microsoft Entra B2C’s edit profile page.
You can pass this URL to your template and render it there.
- login_required(function=None, /, *, scopes: List[str] | None = None)¶
A decorator that ensures the user to be logged in, and optinoally also have consented to a list of scopes.
A user not meeting the requirement(s) will be brought to the login page. For already logged-in user, the view will be called with a keyword argument named “context” which is a dict containing the user object.
Usage:
@settings.AUTH.login_required def my_view(request, *, context): return render(request, 'index.html', dict( user=context["user"], # User is guaranteed to be present # because we decorated this view with @login_required ))
- Parameters:
scopes¶ (list[str]) –
A list of scopes that your app will need to use. When present, the context will also contain an “access_token”, “token_type”, and likely “expires_in” and “refresh_token”.
Usage:
@settings.AUTH.login_required(scopes=["scope1", "scope2"]) def my_view2(request, *, context): api_result = requests.get( # Use access token to call an api "https://example.com/endpoint", headers={'Authorization': 'Bearer ' + context['access_token']}, timeout=30, ) ...
- logout(request)¶
The logout view.
The logout url is also available with the name “identity.django.logout”. So you can use
{% url "identity.django.logout" %}to get the url from inside a template.