OAuth2 Provider for Django web applications with complete server functionality, token management, and authorization endpoints.
—
Django OAuth Toolkit provides comprehensive Django model classes for managing OAuth2 entities. These models handle applications, tokens, grants, and OIDC ID tokens with full ORM integration, validation, and admin interface support.
OAuth2 client application registration and management with support for different client types and authorization grant types.
class Application(AbstractApplication):
"""
OAuth2 client application model.
Attributes:
client_id (str): Unique client identifier
client_secret (str): Confidential client secret (hashed)
hash_client_secret (bool): Whether to hash client secret on save
name (str): Human-readable application name
user (User): Application owner
redirect_uris (str): Space-separated allowed redirect URIs
post_logout_redirect_uris (str): Space-separated OIDC logout URIs
client_type (str): 'confidential' or 'public'
authorization_grant_type (str): Grant type supported
skip_authorization (bool): Skip user consent screen
algorithm (str): OIDC signing algorithm
allowed_origins (str): CORS allowed origins
created (datetime): Application creation timestamp
updated (datetime): Last modification timestamp
"""
# Client types
CLIENT_CONFIDENTIAL = "confidential"
CLIENT_PUBLIC = "public"
CLIENT_TYPES = (
(CLIENT_CONFIDENTIAL, "Confidential"),
(CLIENT_PUBLIC, "Public"),
)
# Grant types
GRANT_AUTHORIZATION_CODE = "authorization-code"
GRANT_IMPLICIT = "implicit"
GRANT_PASSWORD = "password"
GRANT_CLIENT_CREDENTIALS = "client-credentials"
GRANT_OPENID_HYBRID = "openid-hybrid"
GRANT_TYPES = (
(GRANT_AUTHORIZATION_CODE, "Authorization code"),
(GRANT_IMPLICIT, "Implicit"),
(GRANT_PASSWORD, "Resource owner password-based"),
(GRANT_CLIENT_CREDENTIALS, "Client credentials"),
(GRANT_OPENID_HYBRID, "OpenID connect hybrid"),
)
# OIDC algorithms
NO_ALGORITHM = ""
RS256_ALGORITHM = "RS256"
HS256_ALGORITHM = "HS256"
ALGORITHM_TYPES = (
(NO_ALGORITHM, "No OIDC support"),
(RS256_ALGORITHM, "RSA with SHA-2 256"),
(HS256_ALGORITHM, "HMAC with SHA-2 256"),
)
objects = ApplicationManager()
def redirect_uri_allowed(self, uri: str) -> bool:
"""Check if URI is allowed for redirect"""
def post_logout_redirect_uri_allowed(self, uri: str) -> bool:
"""Check if URI is allowed for OIDC logout redirect"""
def origin_allowed(self, origin: str) -> bool:
"""Check if origin is allowed for CORS"""
def allows_grant_type(self, *grant_types: str) -> bool:
"""Check if application supports given grant types"""
def is_usable(self, request) -> bool:
"""Check if application can be used for request"""
@property
def default_redirect_uri(self) -> str:
"""Get default redirect URI if only one exists"""
@property
def jwk_key(self):
"""Get JWK key for OIDC signing"""
class ApplicationManager(models.Manager):
def get_by_natural_key(self, client_id: str) -> Application:
"""Get application by client ID"""OAuth2 access tokens with scope validation, expiration checking, and revocation support.
class AccessToken(AbstractAccessToken):
"""
OAuth2 access token model.
Attributes:
token (str): The access token value
token_checksum (str): SHA-256 checksum of token
user (User): Token owner
application (Application): Associated client application
expires (datetime): Token expiration time
scope (str): Space-separated granted scopes
source_refresh_token (RefreshToken): Source refresh token if any
id_token (IDToken): Associated OIDC ID token if any
"""
def is_valid(self, scopes=None) -> bool:
"""
Check if access token is valid.
Args:
scopes: Optional list of required scopes
Returns:
True if token is not expired and has required scopes
"""
def is_expired(self) -> bool:
"""Check if token has expired"""
def allow_scopes(self, scopes) -> bool:
"""
Check if token allows the provided scopes.
Args:
scopes: Iterable of scope names to check
Returns:
True if all scopes are allowed
"""
def revoke(self) -> None:
"""Revoke the access token by deleting it"""
@property
def scopes(self) -> dict:
"""Get dictionary of allowed scope names with descriptions"""OAuth2 refresh tokens for obtaining new access tokens with revocation and family tracking.
class RefreshToken(AbstractRefreshToken):
"""
OAuth2 refresh token model.
Attributes:
token (str): The refresh token value
user (User): Token owner
application (Application): Associated client application
access_token (AccessToken): Associated access token
token_family (UUID): Token family for rotation tracking
revoked (datetime): Revocation timestamp if revoked
"""
def revoke(self) -> None:
"""
Revoke refresh token and associated access token.
Handles atomic operations and prevents race conditions.
"""OAuth2 authorization grants for the authorization code flow with PKCE support.
class Grant(AbstractGrant):
"""
OAuth2 authorization grant model.
Attributes:
user (User): User who authorized the grant
code (str): Authorization code
application (Application): Client application
expires (datetime): Grant expiration time
redirect_uri (str): Redirect URI for this grant
scope (str): Granted scopes
code_challenge (str): PKCE code challenge
code_challenge_method (str): PKCE challenge method ('plain' or 'S256')
nonce (str): OIDC nonce value
claims (str): OIDC claims parameter
"""
CODE_CHALLENGE_PLAIN = "plain"
CODE_CHALLENGE_S256 = "S256"
CODE_CHALLENGE_METHODS = (
(CODE_CHALLENGE_PLAIN, "plain"),
(CODE_CHALLENGE_S256, "S256")
)
def is_expired(self) -> bool:
"""Check if grant has expired"""
def redirect_uri_allowed(self, uri: str) -> bool:
"""Check if URI matches grant's redirect URI"""OpenID Connect ID tokens for identity information with JWT token ID tracking.
class IDToken(AbstractIDToken):
"""
OIDC ID token model.
Attributes:
jti (UUID): JWT Token ID for unique identification
user (User): Token subject
application (Application): Client application
expires (datetime): Token expiration time
scope (str): Token scopes
"""
def is_valid(self, scopes=None) -> bool:
"""Check if ID token is valid and has required scopes"""
def is_expired(self) -> bool:
"""Check if token has expired"""
def allow_scopes(self, scopes) -> bool:
"""Check if token allows the provided scopes"""
def revoke(self) -> None:
"""Revoke the ID token by deleting it"""
@property
def scopes(self) -> dict:
"""Get dictionary of allowed scope names with descriptions"""Functions to get the active model classes, supporting Django's swappable model system.
def get_application_model():
"""Return the Application model class active in this project"""
def get_access_token_model():
"""Return the AccessToken model class active in this project"""
def get_refresh_token_model():
"""Return the RefreshToken model class active in this project"""
def get_grant_model():
"""Return the Grant model class active in this project"""
def get_id_token_model():
"""Return the IDToken model class active in this project"""Utility functions for managing token lifecycle and cleanup.
def clear_expired() -> None:
"""
Remove all expired tokens and grants from the database.
Handles batch deletion to avoid memory issues with large datasets.
Processes refresh tokens, access tokens, ID tokens, and grants.
"""Helper functions for URI and origin validation.
def redirect_to_uri_allowed(uri: str, allowed_uris: list) -> bool:
"""
Check if URI can be redirected to based on allowed URIs.
Handles exact matches and RFC 8252 loopback IP rules.
Args:
uri: URI to validate
allowed_uris: List of allowed redirect URIs
Returns:
True if redirect is allowed
"""
def is_origin_allowed(origin: str, allowed_origins: list) -> bool:
"""
Check if origin is allowed based on CORS configuration.
Args:
origin: Origin URI to validate
allowed_origins: List of allowed origin URIs
Returns:
True if origin is allowed
"""Factory functions for retrieving active admin classes for OAuth2 models. These functions return the admin classes configured through Django settings.
def get_application_admin_class():
"""Return the Application admin class that is active in this project."""
def get_access_token_admin_class():
"""Return the AccessToken admin class that is active in this project."""
def get_grant_admin_class():
"""Return the Grant admin class that is active in this project."""
def get_id_token_admin_class():
"""Return the IDToken admin class that is active in this project."""
def get_refresh_token_admin_class():
"""Return the RefreshToken admin class that is active in this project."""from oauth2_provider.models import Application
# Confidential web application
web_app = Application.objects.create(
name="My Web Application",
client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
redirect_uris="http://localhost:8000/callback/",
)
# Public mobile application
mobile_app = Application.objects.create(
name="My Mobile App",
client_type=Application.CLIENT_PUBLIC,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
redirect_uris="myapp://callback/",
)from oauth2_provider.models import AccessToken, get_access_token_model
# Check token validity
token = AccessToken.objects.get(token="your-token-here")
if token.is_valid(['read', 'write']):
print("Token is valid for read/write operations")
# Revoke tokens
token.revoke()
# Clean up expired tokens
from oauth2_provider.models import clear_expired
clear_expired()# Access related objects
application = Application.objects.get(client_id="your-client-id")
tokens = application.accesstoken_set.filter(expires__gt=timezone.now())
# Get user's applications
user_apps = Application.objects.filter(user=request.user)
# Get user's authorized tokens
user_tokens = AccessToken.objects.filter(user=request.user)Install with Tessl CLI
npx tessl i tessl/pypi-django-oauth-toolkit