Skip to main content

Django Azure Active Directory Sign-In 🔑

Django 4.1 Python 3.11 License EUPL 1.2 Code style: black CodeQL codecov PyPI Become a sponsor to JV-conseil Follow JV conseil on StackOverflow Follow JVconseil on Twitter Follow JVconseil on Mastodon Follow JV conseil on GitHub

Sign-in users to your Django Web app with Azure Active Directory.

Description

django-azure-active-directory-signin is a Django app which wraps MSAL package to sign in users with Microsoft's Azure Active Directory (OAuth 2.0 and OpenID Connect) in Django projects.

Sign-in users to your Django Web app with Azure Active Directory

The app includes login, logout and callback authentication views, a customizable backend to validate, create user and extend user with extra attributes, a decorator to protect individual views to protect individual views, and middleware which allows the entire site to require user authentication by default, with the ability to exempt specified views.

The GitHub repository provides a demo Django app to run local tests on https protocol thanks to django-sslserver.

This project is in no way affiliated with Microsoft Corporation.

Installation

From PyPi:

pip install django-azure-active-directory-signin

Configuration

Azure App Registration

Register an application. You must have permission to manage applications in Azure Active Directory (Azure AD) on your Azure account.

Add a client secret in Certificates & secrets > Client secrets > New client secret and note it down.

Add a client secret

Copy your client_id, tenant_id and client_secret and store them in environment variables (see .env folder for sample) or better still in an Azure Key Vault.

Obfuscate your credentials by using environment variables

Add redirect URI like so:

  • https://<your-domain>/azure-signin/callback
  • https://127.0.0.1:8000/azure-signin/callback
  • https://localhost:8000/azure-signin/callback

Settings

Add the following to your settings.py, replacing the variables in braces with the values from your Azure app:

INSTALLED_APPS += [
    "azure_signin",
]

AZURE_SIGNIN = {
    "CLIENT_ID": os.environ.get("CLIENT_ID"),  # Mandatory
    "CLIENT_SECRET": os.environ.get("CLIENT_SECRET"),  # Mandatory
    "TENANT_ID": os.environ.get("TENANT_ID"),  # Mandatory
    "SAVE_ID_TOKEN_CLAIMS": True,  # Optional, default is False.
    "RENAME_ATTRIBUTES": [
        ("employeeNumber", "employee_id"),
        ("affiliationNumber", "omk2"),
    ],  # Optional
    "REDIRECT_URI": "https://<domain>/azure-signin/callback",  # Optional
    "SCOPES": ["User.Read.All"],  # Optional
    "AUTHORITY": "https://login.microsoftonline.com/" + os.environ.get("TENANT_ID"),  # Optional Or https://login.microsoftonline.com/common if multi-tenant
    "LOGOUT_REDIRECT_URI": "https://<domain>/logout",  # Optional
    "PUBLIC_URLS": ["<public:view_name>",]  # Optional, public views accessible by non-authenticated users
}

AUTHENTICATION_BACKENDS += [
    "azure_signin.backends.AzureSigninBackend",
]

LOGIN_URL = "azure_signin:login"
LOGIN_REDIRECT_URL = "/" # Or any other endpoint
LOGOUT_REDIRECT_URL = LOGIN_REDIRECT_URL

Installed apps

Add the following to your INSTALLED_APPS:

INSTALLED_APPS += [
    "azure_signin",
]

Authentication backend

Configure the authentication backend:

AUTHENTICATION_BACKENDS += [
    "azure_signin.backends.AzureSigninBackend",
]

URLs

Include the app's URLs in your urlpatterns:

from django.urls import path, include

urlpatterns += [
    path("azure-signin/", include("azure_signin.urls", namespace="azure_signin")),
]

Usage

AbstractUser

Add extra attributes to users with AZURE_SIGNIN["RENAME_ATTRIBUTES"] and Django django.contrib.auth.models.AbstractUser.

from django.contrib.auth.models import AbstractUser
from django.db import models


class ExtendedUser(AbstractUser):
    """
    Extend user with extra attributes set in `AZURE_SIGNIN["RENAME_ATTRIBUTES"]`
    """

    email = models.EmailField(unique=True, db_index=True)
    employee_id = models.IntegerField(
        null=True, default=None, unique=True, blank=True, db_index=True
    )
    omk2 = models.CharField(max_length=5, null=True, default=None, db_index=True)
    hcm = models.CharField(max_length=7, null=True, default=None, db_index=True)

Backend

Backend can be subclassed to customize validation rules for user.

import logging

from azure_signin.backends import AzureSigninBackend

logger = logging.getLogger(__name__)

class CustomAzureSigninBackend(AzureSigninBackend):
    "Subclass AzureSigninBackend to customize validation rules for user."

    def is_valid_user(self, user: dict, *args, **kwargs) -> bool:
        "is_valid_user"
        output = super().is_valid_user(user, *args, **kwargs)
        try:
            "run extra checks here..."
            pass
        except Exception as e:
            logger.exception(e)
        logger.debug("is_valid_user: %s", output)
        return output

Decorator

To make user authentication a requirement for accessing an individual view, decorate the view like so:

from azure_signin.decorators import azure_signin_required
from django.shortcuts import HttpResponse

@azure_signin_required
def protected_view(request):
    return HttpResponse("A view protected by the decorator")

Middleware

If you want to protect your entire site by default, you can use the middleware by adding the following to your settings.py:

MIDDLEWARE += [
    "azure_signin.middleware.AzureSigninMiddleware",
]

Make sure you add the middleware after Django's session and authentication middlewares so that the request includes the session and user objects. Public URLs which need to be accessed by non-authenticated users should be specified in the settings.AZURE_SIGNIN["PUBLIC_URLS"], as shown above.

VS Code Tasks

The GitHub repository provides commands Install, Launch and Tests accessible through Command Palette (press Cmd+Shift+P) then >Tasks: Run Tasks.

VS Code Tasks The app includes Install, Launch and Tests commands accessible through Command Palette > Tasks: Run Tasks (press Cmd+Shift+P)

All bash scripts are stored in .bash folder.

The virtual environment is propelled by poetry which can be installed with Homebrew brew install poetry.

Credits

This app is inspired by and builds on functionality in https://github.com/AgileTek/django-azure-auth, with both feature improvements, code coverage and extended documentation.

Readings 📚

Sponsorship

If this project helps you, you can offer me a cup of coffee ☕️ :-)

Become a sponsor to JV-conseil

Metadata

Release files for django-azure-active-directory-signin 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-azure-active-directory-signin 0.2.1
File Size Uploaded Provenance Actions
django_azure_active_directory_signin-0.2.1.tar.gz 19.5 kB Without provenance Details for django_azure_active_directory_signin-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-azure-active-directory-signin 0.2.1
File Interpreter ABI Platform Actions
django_azure_active_directory_signin-0.2.1-py3-none-any.whl Python 3 none any Details for django_azure_active_directory_signin-0.2.1-py3-none-any.whl

Total release size: 39.2 kB

Release files / django_azure_active_directory_signin-0.2.1.tar.gz

Download URL django_azure_active_directory_signin-0.2.1.tar.gz
Size 19.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f0b019bf4689b404f8877ef41feafea31408ebfa90e4db967c07820dd007ae2c
BLAKE2b-256 checksum
How to use checksums
ceef2d2ace474af38df5651f6e47f60858ecaec0fdcaecde446ecfb3c669295a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.4.1 CPython/3.11.2 Darwin/21.6.0

Release files / django_azure_active_directory_signin-0.2.1-py3-none-any.whl

Download URL django_azure_active_directory_signin-0.2.1-py3-none-any.whl
Size 19.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
64a85926ed2dcffda4c4e83e569131d46c490f926480a458f51d2a01ebbe3067
BLAKE2b-256 checksum
How to use checksums
e9323606330cc8757fae5f22a81ecd722e1819963c8b37482fd0962992d5d462
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.4.1 CPython/3.11.2 Darwin/21.6.0

Security for django-azure-active-directory-signin 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page