API Reference#
This page contains the full API reference for axioms-drf-py, automatically generated from the source code docstrings.
Core Configuration#
The SDK requires the following Django settings to be configured:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Expected audience claim in the JWT token. |
|
No |
Axioms domain name. Used as the base to construct |
|
No |
Full issuer URL for validating the |
|
No |
Full URL to JWKS endpoint (e.g.,
|
Important
Either AXIOMS_JWKS_URL, AXIOMS_ISS_URL, or AXIOMS_DOMAIN must be configured for token validation.
Configuration Hierarchy:
The SDK uses the following construction order:
AXIOMS_DOMAIN→ constructs →AXIOMS_ISS_URL(if not explicitly set)AXIOMS_ISS_URL→ constructs →AXIOMS_JWKS_URL(if not explicitly set)
Example: Setting only AXIOMS_DOMAIN=auth.example.com/oauth results in:
AXIOMS_ISS_URL:https://auth.example.com/oauthAXIOMS_JWKS_URL:https://auth.example.com/oauth/.well-known/jwks.json
Security & Algorithm Validation#
The SDK implements multiple security best practices to prevent common JWT attacks:
Algorithm Validation
Only secure asymmetric algorithms are accepted for JWT signature verification. The SDK validates that:
The
algheader in the JWT specifies an allowed algorithmEach key is used with exactly one algorithm
The algorithm validation occurs before cryptographic operations
Supported Algorithms:
RSA: RS256, RS384, RS512
ECDSA: ES256, ES384, ES512
RSA-PSS: PS256, PS384, PS512
Rejected Algorithms:
none- No signature (critical security vulnerability)HS256,HS384,HS512- Symmetric algorithms (prevents key confusion attacks)Any algorithm not in the allowed list above
This prevents algorithm confusion attacks where an attacker might try to:
Use the
nonealgorithm to bypass signature verificationSubstitute an asymmetric algorithm with a symmetric one
Use weak or deprecated algorithms
Additional Security Features:
Issuer validation (
issclaim) to prevent token substitutionAutomatic public key retrieval and validation from JWKS endpoints
Token expiration validation
Audience claim validation
Key ID (
kid) validation
Claim Name Mapping#
Configure custom claim names to support different authorization servers (AWS Cognito, Auth0, Okta, Microsoft Entra). These mapping options provide additional customization for claim names used to extract scopes, roles, and permissions from the JWT token. These mappings can also support RFC 9068 JWT Profile for OAuth 2.0 Access Tokens.
Parameter |
Required |
Description |
|---|---|---|
|
No |
List of scope claim names to check in priority order. Default: Example: |
|
No |
List of role claim names to check in priority order. Default: Example: |
|
No |
List of permission claim names to check in priority order. Default: Example: |
Important
Namespaced Claims: You can specify namespaced claim names directly in the claim configuration lists.
The SDK will check claims in the order you specify them, using the first non-None value found.
Example: AXIOMS_ROLES_CLAIMS = ['roles', 'https://myapp.com/claims/roles', 'cognito:groups']
Setting Django Settings#
You can configure these settings in your Django settings.py file:
# Required
AXIOMS_AUDIENCE = 'your-api-audience-or-resource-identifier'
# Option 1: Use AXIOMS_DOMAIN (simplest)
AXIOMS_DOMAIN = 'your-domain.axioms.io'
# Option 2: Use AXIOMS_ISS_URL (more control)
# AXIOMS_ISS_URL = 'https://my-auth.domain.com/oauth2'
# Option 3: Use AXIOMS_JWKS_URL (full control)
# AXIOMS_JWKS_URL = 'https://my-auth.domain.com/oauth2/.well-known/jwks.json'
# Optional: Custom claim names
# AXIOMS_SCOPE_CLAIMS = ['scope', 'scp']
# AXIOMS_ROLES_CLAIMS = ['roles', 'cognito:groups']
# AXIOMS_PERMISSIONS_CLAIMS = ['permissions', 'custom:permissions']
Middleware#
The middleware module provides Django middleware for JWT token extraction and validation.
Django middleware for JWT token extraction and validation.
This module provides middleware that extracts JWT tokens from the Authorization
header and validates them before the request reaches the view. It sets attributes
on the request object that authentication classes use to determine access.
The middleware must be added to Django’s MIDDLEWARE setting before the request
reaches any views that require authentication.
- Configuration:
Add to Django settings.py:
MIDDLEWARE = [ 'axioms_drf.middleware.AccessTokenMiddleware', # ... other middleware ] # Required settings AXIOMS_AUDIENCE = 'your-api-audience' # Optional settings (one of these is required) AXIOMS_DOMAIN = 'your-auth-domain.com' AXIOMS_ISS_URL = 'https://your-auth-domain.com' AXIOMS_JWKS_URL = 'https://your-auth-domain.com/.well-known/jwks.json'
- Classes:
AccessTokenMiddleware: Main middleware for JWT token processing.
- class AccessTokenMiddleware(get_response)[source]#
Bases:
MiddlewareMixinMiddleware that extracts and validates JWT tokens from
Authorizationheader.This middleware processes incoming requests to extract JWT tokens from the
Authorizationheader, validates them, and sets request attributes that authentication classes use to grant or deny access.- The middleware sets the following attributes on the request:
auth_jwt(Box|False|None): Validated token payload as Box object,Falseifvalidation failed,
Noneif no token provided.
missing_auth_header(bool):TrueifAuthorizationheader is missing.invalid_bearer_token(bool):Trueif Bearer format is invalid.- Token validation includes:
Signature verification using JWKS
Expiration time check
Audience claim validation
Issuer claim validation (if configured)
Algorithm validation (only secure asymmetric algorithms allowed)
The middleware catches all validation exceptions and sets
auth_jwt=False, allowing authentication classes to handle the error appropriately.Example:
# In settings.py MIDDLEWARE = [ 'axioms_drf.middleware.AccessTokenMiddleware', 'django.middleware.common.CommonMiddleware', # ... other middleware ] AXIOMS_AUDIENCE = 'my-api' AXIOMS_DOMAIN = 'auth.example.com'
- Raises:
Exception – If required settings are not configured.
AXIOMS_AUDIENCEis always required. At least one JWKS source must be configured:AXIOMS_JWKS_URL,AXIOMS_ISS_URL, orAXIOMS_DOMAIN.
Note
This middleware should be placed early in the middleware stack, before any authentication-dependent middleware.
- process_request(request)[source]#
Process incoming request to extract and validate JWT token.
This method is called for every request before it reaches the view. It extracts the JWT token from the
Authorizationheader, validates it, and sets request attributes for use by authentication classes.- Request attributes set:
auth_jwt: Box object with token payload if valid,Falseif invalid,Noneif missing
missing_auth_header:TrueifAuthorizationheader not presentinvalid_bearer_token:Trueif header doesn’t matchBearer <token>format
- Parameters:
request – Django HttpRequest object.
- Raises:
Exception – If
AXIOMS_AUDIENCEis not configured or if none of the JWKS source settings (AXIOMS_JWKS_URL,AXIOMS_ISS_URL, orAXIOMS_DOMAIN) are configured.- Returns:
This method doesn’t return anything, it modifies the request in-place.
- Return type:
None
JWKS Manager#
The apps module provides Django application configurations for initializing the JWKS manager.
Django AppConfig classes for automatic JWKS manager lifecycle management.
These apps handle initialization and shutdown of the JWKS manager automatically. Users can simply add the appropriate app to their INSTALLED_APPS.
- For standard Django/WSGI applications:
- INSTALLED_APPS = [
‘axioms_drf.apps.JWKSManagerWSGIConfig’, # … other apps
]
- For Django ASGI applications:
- INSTALLED_APPS = [
‘axioms_drf.apps.JWKSManagerASGIConfig’, # … other apps
]
- class JWKSManagerWSGIConfig(app_name, app_module)[source]#
Bases:
AppConfigAppConfig for JWKS manager with background refresh for WSGI applications.
This app automatically initializes the JWKS manager with background refresh on Django startup and properly shuts it down on application exit.
- Usage:
Add to INSTALLED_APPS in settings.py:
- INSTALLED_APPS = [
‘axioms_drf.apps.JWKSManagerWSGIConfig’, # … other apps
]
- Configuration (optional):
AXIOMS_JWKS_REFRESH_INTERVAL = 3600 # Refresh every 1hr (default) AXIOMS_JWKS_CACHE_TTL = 7200 # Cache for 2hrs (default)
For standard Django/WSGI applications. Use JWKSManagerASGIConfig for ASGI.
- name = 'axioms_drf'#
- label = 'axioms_drf_jwks_wsgi'#
- verbose_name = 'Axioms DRF JWKS Manager (WSGI)'#
- class JWKSManagerASGIConfig(app_name, app_module)[source]#
Bases:
AppConfigAppConfig for JWKS manager with background refresh for ASGI applications.
This app automatically initializes the async JWKS manager with background refresh on Django startup and properly shuts it down on application exit.
- Usage:
Add to INSTALLED_APPS in settings.py:
- INSTALLED_APPS = [
‘axioms_drf.apps.JWKSManagerASGIConfig’, # … other apps
]
- Configuration (optional):
AXIOMS_JWKS_REFRESH_INTERVAL = 3600 # Refresh every 1hr (default) AXIOMS_JWKS_CACHE_TTL = 7200 # Cache for 2hrs (default)
For Django ASGI applications. Use JWKSManagerWSGIConfig for WSGI.
- name = 'axioms_drf'#
- label = 'axioms_drf_jwks_asgi'#
- verbose_name = 'Axioms DRF JWKS Manager (ASGI)'#
Authentication Classes#
The authentication module provides Django REST Framework authentication classes for JWT token validation.
Django REST Framework authentication classes for JWT token validation.
This module provides authentication classes that integrate with Django REST Framework
to validate OAuth2/OIDC JWT access tokens. It works in conjunction with the
AccessTokenMiddleware to perform token validation.
- Configuration:
Configure safe HTTP methods that bypass authentication in Django settings:
# Optional: Configure safe HTTP methods (defaults to HEAD and OPTIONS) AXIOMS_SAFE_METHODS = ('HEAD', 'OPTIONS', 'GET')
- Classes:
HasValidAccessToken: Main authentication class requiring valid JWT token.IsAccessTokenAuthenticated: Alias forHasValidAccessToken.IsAnyPostOrIsAccessTokenAuthenticated: Allows POST without authentication.IsAnyGetOrIsAccessTokenAuthenticated: Allows GET without authentication.MissingAuthorizationHeader: Exception for missing Authorization header.InvalidAuthorizationBearer: Exception for invalid Bearer token format.UnauthorizedAccess: Exception for invalid or expired tokens.
Example:
from rest_framework.views import APIView
from rest_framework.response import Response
from axioms_drf.authentication import HasValidAccessToken
class ProtectedView(APIView):
authentication_classes = [HasValidAccessToken]
def get(self, request):
# User is authenticated with valid JWT token
return Response({'user': request.user})
- class HasValidAccessToken[source]#
Bases:
BaseAuthenticationAuthentication class that validates JWT access tokens.
This class integrates with
AccessTokenMiddlewarewhich performs the actual token validation. The middleware setsrequest.auth_jwtwith the validated token payload, or flags for missing/invalid tokens.The authentication succeeds when: - A valid JWT token is present in the
Authorizationheader - The token has not expired - The token has valid signature and claims - The token audience matches configuredAXIOMS_AUDIENCESafe HTTP methods (HEAD, OPTIONS by default) are allowed without authentication to support CORS preflight. Configure
AXIOMS_SAFE_METHODSsetting to customize.- Raises:
MissingAuthorizationHeader – If
Authorizationheader is not present.InvalidAuthorizationBearer – If Bearer token format is invalid.
UnauthorizedAccess – If token is invalid, expired, or has invalid signature.
- Returns:
(user_identifier, auth_success) where user_identifier is the
subclaim.- Return type:
- authenticate(request)[source]#
Authenticate the request using JWT token from middleware.
- Parameters:
request – Django REST Framework request object with
auth_jwtattribute set byAccessTokenMiddleware.- Returns:
(user_identifier, True)if authentication succeeds, whereuser_identifieris the subject claim from the token.
None: If no authentication is required (safe HTTP methods).
- Return type:
- Raises:
MissingAuthorizationHeader – If
Authorizationheader is missing.InvalidAuthorizationBearer – If Bearer format is invalid.
UnauthorizedAccess – If token validation fails.
- class IsAccessTokenAuthenticated[source]#
Bases:
HasValidAccessTokenAlias for
HasValidAccessToken.This class provides the same functionality as
HasValidAccessToken. Use this if you prefer the naming style.
- class IsAnyPostOrIsAccessTokenAuthenticated[source]#
Bases:
HasValidAccessTokenAuthentication class that allows
POSTrequests without authentication.Useful for public endpoints that accept unauthenticated
POSTrequests (e.g., user registration, password reset) but require authentication for other methods.Example:
class RegisterView(APIView): authentication_classes = [IsAnyPostOrIsAccessTokenAuthenticated] def post(self, request): # Anyone can register (no auth required) return Response({'status': 'registered'}) def get(self, request): # Requires valid JWT token return Response({'user': request.user})
- class IsAnyGetOrIsAccessTokenAuthenticated[source]#
Bases:
HasValidAccessTokenAuthentication class that allows
GETrequests without authentication.Useful for public read endpoints that don’t require authentication for viewing but require authentication for modifications.
Example:
class ArticleView(APIView): authentication_classes = [IsAnyGetOrIsAccessTokenAuthenticated] def get(self, request): # Anyone can read articles (no auth required) return Response({'articles': []}) def post(self, request): # Requires valid JWT token to create return Response({'status': 'created'})
- exception MissingAuthorizationHeader(detail=None, code=None)[source]#
Bases:
APIExceptionException raised when
Authorizationheader is missing from request.This exception is raised when a protected endpoint is accessed without providing the
Authorizationheader.Follows RFC 6750 OAuth 2.0 Bearer Token Usage standard.
- status_code#
HTTP 401 Unauthorized
- default_detail#
Error message dict with RFC 6750 compliant error and description
- default_code#
invalid_token
- status_code = 401#
- default_detail = {'error': 'invalid_token', 'error_description': 'Missing Authorization Header'}#
- default_code = 'invalid_token'#
- exception InvalidAuthorizationBearer(detail=None, code=None)[source]#
Bases:
APIExceptionException raised when Bearer token format is invalid.
This exception is raised when the
Authorizationheader is present but doesn’t follow theBearer <token>format.Follows RFC 6750 OAuth 2.0 Bearer Token Usage standard.
- status_code#
HTTP 401 Unauthorized
- default_detail#
Error message dict with RFC 6750 compliant error and description
- default_code#
invalid_token
- status_code = 401#
- default_detail = {'error': 'invalid_token', 'error_description': 'Invalid Authorization Bearer'}#
- default_code = 'invalid_token'#
- exception UnauthorizedAccess(detail=None, code=None)[source]#
Bases:
APIExceptionException raised when JWT token validation fails.
This exception is raised when: - Token signature is invalid - Token has expired - Token audience doesn’t match configured
AXIOMS_AUDIENCE- Token issuer doesn’t match configuredAXIOMS_ISS_URL- Token algorithm is not in allowed algorithms - Token is missing required claimsFollows RFC 6750 OAuth 2.0 Bearer Token Usage standard.
- status_code#
HTTP 401 Unauthorized
- default_detail#
Error message dict with RFC 6750 compliant error and description
- default_code#
invalid_token
- status_code = 401#
- default_detail = {'error': 'invalid_token', 'error_description': 'Invalid access token'}#
- default_code = 'invalid_token'#
Permission Classes#
The permissions module provides Django REST Framework permission classes for claim-based authorization.
Django REST Framework permission classes for JWT claim-based authorization.
This module provides permission classes that perform authorization based on claims in validated JWT tokens (scopes, roles, permissions). These classes work with the authentication classes and middleware to provide fine-grained access control.
- Permission Logic:
Each permission class supports both OR and AND logic through different attributes: -
_any_attributes: User needs ANY ONE of the specified claims (OR logic) -_all_attributes: User needs ALL of the specified claims (AND logic)- Configuration:
Configure custom claim names in Django settings:
# Optional: Configure custom claim names for roles AXIOMS_ROLES_CLAIMS = ['roles', 'https://example.com/claims/roles'] # Optional: Configure custom claim names for permissions AXIOMS_PERMISSIONS_CLAIMS = ['permissions', 'https://example.com/claims/permissions'] # Optional: Configure custom claim names for scopes AXIOMS_SCOPE_CLAIMS = ['scope', 'scp']
- Classes:
HasAccessTokenScopes: Check scopes (supports both OR and AND logic).HasAccessTokenRoles: Check roles (supports both OR and AND logic).HasAccessTokenPermissions: Check permissions (supports both OR and AND logic).IsSubOwner: Object-level permission for token subject ownership.IsSubOwnerOrSafeOnly: Object-level permission allowing safe methods or owner access.IsSafeOnly: Permission allowing only safe HTTP methods.InsufficientPermission: Exception raised when authorization fails.
Example:
from rest_framework.views import APIView
from rest_framework.response import Response
from axioms_drf.authentication import HasValidAccessToken
from axioms_drf.permissions import HasAccessTokenScopes, HasAccessTokenRoles
# OR logic - user needs ANY ONE scope
class DataView(APIView):
authentication_classes = [HasValidAccessToken]
permission_classes = [HasAccessTokenScopes]
access_token_scopes = ['read:data', 'write:data'] # OR logic (backward compatible)
# OR use: access_token_any_scopes = ['read:data', 'write:data']
def get(self, request):
return Response({'data': 'protected'})
# AND logic - user needs ALL scopes
class SecureView(APIView):
authentication_classes = [HasValidAccessToken]
permission_classes = [HasAccessTokenScopes]
access_token_all_scopes = ['read:data', 'write:data'] # AND logic
def post(self, request):
return Response({'status': 'created'})
- class HasAccessTokenScopes[source]#
Bases:
BasePermissionPermission class that checks if user has required scopes.
Supports both OR logic (any scope) and AND logic (all scopes) through different view attributes:
access_token_scopesoraccess_token_any_scopes: User needs ANY ONE (OR logic)access_token_all_scopes: User needs ALL (AND logic)
- access_token_scopes#
List of scopes (OR logic, backward compatible).
- access_token_any_scopes#
List of scopes (OR logic, explicit).
- access_token_all_scopes#
List of scopes (AND logic).
Example:
# OR logic - user needs read OR write class DataView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenScopes] access_token_scopes = ['read:data', 'write:data'] # AND logic - user needs BOTH read AND write class SecureView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenScopes] access_token_all_scopes = ['read:data', 'write:data'] # Method-level scopes - different scopes for each HTTP method class MethodLevelView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenScopes] @property def access_token_scopes(self): method_scopes = { 'GET': ['read:data'], 'POST': ['write:data'], 'DELETE': ['delete:data'] } return method_scopes[self.request.method] def get(self, request): return Response({'data': []}) def post(self, request): return Response({'status': 'created'}) # ViewSet with action-specific scopes from rest_framework import viewsets class ArticleViewSet(viewsets.ModelViewSet): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenScopes] queryset = Article.objects.all() serializer_class = ArticleSerializer @property def access_token_scopes(self): action_scopes = { 'list': ['article:read'], 'retrieve': ['article:read'], 'create': ['article:create'], 'update': ['article:update'], 'partial_update': ['article:update'], 'destroy': ['article:delete'], } return action_scopes.get(self.action, [])
- Raises:
InsufficientPermission – If user doesn’t have required scopes.
ImproperlyConfigured – If no scope attribute is defined on the view.
- message = 'Permission Denied'#
- has_permission(request, view)[source]#
Check if user has required scopes.
- Parameters:
request – Django REST Framework request with
auth_jwtattribute.view – View instance with scope attributes.
- Returns:
Trueif user has required scopes.- Return type:
- Raises:
InsufficientPermission – If authorization fails.
- class HasAccessTokenRoles[source]#
Bases:
BasePermissionPermission class that checks if user has required roles.
Supports both OR logic (any role) and AND logic (all roles) through different view attributes:
access_token_rolesoraccess_token_any_roles: User needs ANY ONE (OR logic)access_token_all_roles: User needs ALL (AND logic)
- access_token_roles#
List of roles (OR logic, backward compatible).
- access_token_any_roles#
List of roles (OR logic, explicit).
- access_token_all_roles#
List of roles (AND logic).
Example:
# OR logic - user needs admin OR moderator class AdminView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenRoles] access_token_roles = ['admin', 'moderator'] # AND logic - user needs BOTH admin AND superuser class SuperAdminView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenRoles] access_token_all_roles = ['admin', 'superuser'] # Method-level roles - different roles for each HTTP method class MethodLevelView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenRoles] @property def access_token_roles(self): method_roles = { 'GET': ['viewer', 'editor'], 'POST': ['editor', 'admin'], 'DELETE': ['admin'] } return method_roles[self.request.method] def get(self, request): return Response({'data': []}) def post(self, request): return Response({'status': 'created'}) # ViewSet with action-specific roles from rest_framework import viewsets class UserViewSet(viewsets.ModelViewSet): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenRoles] queryset = User.objects.all() serializer_class = UserSerializer @property def access_token_roles(self): action_roles = { 'list': ['viewer', 'editor', 'admin'], 'retrieve': ['viewer', 'editor', 'admin'], 'create': ['admin'], 'update': ['editor', 'admin'], 'partial_update': ['editor', 'admin'], 'destroy': ['admin'], } return action_roles.get(self.action, [])
- Raises:
InsufficientPermission – If user doesn’t have required roles.
ImproperlyConfigured – If no role attribute is defined on the view.
- message = 'Permission Denied'#
- has_permission(request, view)[source]#
Check if user has required roles.
- Parameters:
request – Django REST Framework request with
auth_jwtattribute.view – View instance with role attributes.
- Returns:
Trueif user has required roles.- Return type:
- Raises:
InsufficientPermission – If authorization fails.
- class HasAccessTokenPermissions[source]#
Bases:
BasePermissionPermission class that checks if user has required permissions.
Supports both OR logic (any permission) and AND logic (all permissions) through different view attributes:
access_token_permissionsoraccess_token_any_permissions: User needs ANY ONE (OR logic)access_token_all_permissions: User needs ALL (AND logic)
- access_token_permissions#
List of permissions (OR logic, backward compatible).
- access_token_any_permissions#
List of permissions (OR logic, explicit).
- access_token_all_permissions#
List of permissions (AND logic).
Example:
# OR logic - user needs read OR admin permission class UserView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenPermissions] access_token_permissions = ['user:read', 'user:admin'] # AND logic - user needs BOTH write AND delete class CriticalView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenPermissions] access_token_all_permissions = ['user:write', 'user:delete'] # Method-level permissions - different permission for each HTTP method class MethodLevelView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenPermissions] @property def access_token_permissions(self): method_permissions = { 'GET': ['user:read'], 'POST': ['user:create'], 'PATCH': ['user:update'], 'DELETE': ['user:delete'] } return method_permissions[self.request.method] def get(self, request): return Response({'message': 'User read.'}) def post(self, request): return Response({'message': 'User created.'}) # ViewSet with action-specific permissions from rest_framework import viewsets class DocumentViewSet(viewsets.ModelViewSet): authentication_classes = [HasValidAccessToken] permission_classes = [HasAccessTokenPermissions] queryset = Document.objects.all() serializer_class = DocumentSerializer @property def access_token_permissions(self): action_permissions = { 'list': ['document:read'], 'retrieve': ['document:read'], 'create': ['document:create'], 'update': ['document:update'], 'partial_update': ['document:update'], 'destroy': ['document:delete'], } return action_permissions.get(self.action, [])
- Raises:
InsufficientPermission – If user doesn’t have required permissions.
ImproperlyConfigured – If no permission attribute is defined on the view.
- message = 'Permission Denied'#
- has_permission(request, view)[source]#
Check if user has required permissions.
- Parameters:
request – Django REST Framework request with
auth_jwtattribute.view – View instance with permission attributes.
- Returns:
Trueif user has required permissions.- Return type:
- Raises:
InsufficientPermission – If authorization fails.
- class IsSubOwner[source]#
Bases:
BasePermissionObject-level permission that checks if the token subject matches the object owner.
This permission class checks if the
sub(subject) claim from the JWT token matches a specified attribute on the object being accessed. This is useful for ensuring users can only access their own resources.- owner_attribute#
Name of the object attribute to compare with token
sub. Defaults to'user'.
Example:
# Basic usage - compares token sub with object.owner class ArticleDetailView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [IsSubOwner] owner_attribute = 'author_id' # Compare with object.author_id def get_object(self): return Article.objects.get(pk=self.kwargs['pk']) def get(self, request, pk): article = self.get_object() self.check_object_permissions(request, article) return Response({'title': article.title}) # Using with ViewSet class ArticleViewSet(viewsets.ModelViewSet): authentication_classes = [HasValidAccessToken] permission_classes = [IsSubOwner] owner_attribute = 'user_id' queryset = Article.objects.all() serializer_class = ArticleSerializer
- Raises:
InsufficientPermission – If token subject doesn’t match object owner.
ImproperlyConfigured – If
owner_attributeis not defined.
- message = 'Permission Denied - Not the owner'#
- has_object_permission(request, view, obj)[source]#
Check if token subject matches object owner attribute.
- Parameters:
request – Django REST Framework request with
auth_jwtattribute.view – View instance with
owner_attribute.obj – Object being accessed.
- Returns:
Trueif token subject matches object owner.- Return type:
- Raises:
InsufficientPermission – If authorization fails.
ImproperlyConfigured – If owner_attribute is not set or object doesn’t have the attribute.
- class IsSubOwnerOrSafeOnly[source]#
Bases:
BasePermissionObject-level permission for safe methods or owner-only modifications.
Allows safe HTTP methods (GET, HEAD, OPTIONS by default) for all authenticated users, but restricts unsafe methods (POST, PUT, PATCH, DELETE) to the object owner. Owner is determined by comparing the token
subclaim with a specified object attribute.- owner_attribute#
Name of the object attribute to compare with token
sub. Defaults to'owner'.
- safe_methods#
Tuple of HTTP methods considered safe. Defaults to
('GET', 'HEAD', 'OPTIONS').
Example:
# Allow anyone to read, but only owner can update/delete class ArticleDetailView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [IsSubOwnerOrSafeOnly] owner_attribute = 'author_id' safe_methods = ('GET', 'HEAD', 'OPTIONS') def get_object(self): return Article.objects.get(pk=self.kwargs['pk']) def get(self, request, pk): # Anyone can read article = self.get_object() self.check_object_permissions(request, article) return Response({'title': article.title}) def put(self, request, pk): # Only owner can update article = self.get_object() self.check_object_permissions(request, article) # Update logic return Response({'status': 'updated'}) # Using with ViewSet class ArticleViewSet(viewsets.ModelViewSet): authentication_classes = [HasValidAccessToken] permission_classes = [IsSubOwnerOrSafeOnly] owner_attribute = 'user_id' safe_methods = ('GET', 'HEAD', 'OPTIONS', 'LIST') queryset = Article.objects.all() serializer_class = ArticleSerializer
- Raises:
InsufficientPermission – If non-safe method and token subject doesn’t match owner.
ImproperlyConfigured – If
owner_attributeis not defined.
- message = 'Permission Denied - Safe methods only or must be owner'#
- has_object_permission(request, view, obj)[source]#
Check if request method is safe or token subject matches owner.
- Parameters:
request – Django REST Framework request with
auth_jwtandmethod.view – View instance with
owner_attributeandsafe_methods.obj – Object being accessed.
- Returns:
Trueif method is safe or user is owner.- Return type:
- Raises:
InsufficientPermission – If authorization fails.
- class IsSafeOnly[source]#
Bases:
BasePermissionPermission that only allows safe HTTP methods.
Restricts access to safe HTTP methods only (GET, HEAD, OPTIONS by default). Useful for read-only endpoints where authenticated users can view but not modify.
- safe_methods#
Tuple of HTTP methods considered safe. Defaults to
('GET', 'HEAD', 'OPTIONS').
Example:
# Read-only access for all authenticated users class ArticleListView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [IsSafeOnly] safe_methods = ('GET', 'HEAD', 'OPTIONS') def get(self, request): articles = Article.objects.all() return Response({'articles': list(articles.values())}) def post(self, request): # This will be denied by IsSafeOnly permission return Response({'status': 'created'}) # Custom safe methods including LIST class CustomReadOnlyView(APIView): authentication_classes = [HasValidAccessToken] permission_classes = [IsSafeOnly] safe_methods = ('GET', 'HEAD', 'OPTIONS', 'LIST') def get(self, request): return Response({'data': 'read-only'})
- Raises:
InsufficientPermission – If request method is not in safe_methods.
- message = 'Permission Denied - Safe methods only'#
- has_permission(request, view)[source]#
Check if request method is safe.
- Parameters:
request – Django REST Framework request with
method.view – View instance with optional
safe_methodsattribute.
- Returns:
Trueif method is safe.- Return type:
- Raises:
InsufficientPermission – If method is not safe.
- exception InsufficientPermission(detail=None, code=None)[source]#
Bases:
APIExceptionException raised when user lacks required scopes, roles, or permissions.
This exception is raised by permission classes when a user’s JWT token doesn’t contain the required claims for accessing a protected endpoint.
Follows RFC 6750 OAuth 2.0 Bearer Token Usage standard.
- status_code#
HTTP 403 Forbidden
- default_detail#
Error message dict with RFC 6750 compliant error and description
- default_code#
insufficient_scope
Example:
# Automatically raised by permission classes class ProtectedView(APIView): permission_classes = [HasAccessTokenScopes] access_token_scopes = ['admin'] def get(self, request): # InsufficientPermission raised if user lacks 'admin' scope return Response({'data': 'protected'})
- status_code = 403#
- default_detail = {'error': 'insufficient_scope', 'error_description': 'Insufficient role, scope or permission'}#
- default_code = 'insufficient_scope'#
Helper Functions#
The helper module provides utility functions for token validation and claim extraction.
Token validation helpers for Axioms DRF.
This module provides helper functions for JWT token validation with support for algorithm validation, issuer validation, and configuration hierarchy.
- build_config_from_django_settings()[source]#
Build configuration dict from Django settings for axioms-core-py.
- Returns:
Configuration dictionary compatible with axioms-core-py.
- Return type:
- has_valid_token(token)[source]#
Validate JWT token with algorithm and issuer validation.
- Parameters:
token – JWT token string.
- Returns:
- Immutable (frozen) Box containing validated JWT payload. The returned Box
cannot be modified to prevent tampering with validated token claims.
- Return type:
Box
- Raises:
UnauthorizedAccess – If token is invalid.