Ninja JWT
repository·master·Indexed 42 days ago
https://github.com/eadwincode/django-ninja-jwtA JSON Web Token (JWT) plugin for Django-Ninja, forked from Simple JWT to remove Django REST Framework dependencies. It provides JWT authentication for both class-based controllers and function-based routers, including support for asynchronous routes via AsyncJWTAuth, token blacklisting, and custom token claim configuration via schema swapping.
What's inside Ninja JWT
- Ninja JWT is a plugin for Django Ninja that provides JSON Web Token (JWT) authentication. It is designed to handle common JWT use cases with a robust authentication backend and a practical set of default features. The library is highly extensible, allowing developers to implement custom authentication logic or features.
Understand Ninja JWT token types
masterNinja JWT uses a
token_typeclaim (customizable viaTOKEN_TYPE_CLAIM) in the token payload to distinguish between different authentication tokens.Supported types include:
access: The default token type used for authentication.sliding: A token that contains both an expiration claim and a refresh expiration claim.refresh: Used for obtaining new tokens, but is not considered valid for direct authentication.
By default, the library expects an
accesstoken. You can control which token types are valid for authentication by configuring theAUTH_TOKEN_CLASSESsetting with dot paths to the appropriate token classes.Blacklist a token via Django Admin
masterThe blacklist app provides two models with defined admins:
OutstandingTokenandBlacklistedToken.To blacklist a token manually via the admin interface:
- Locate the corresponding
OutstandingTokenrecord in the Django admin. - Create a new
BlacklistedTokenrecord that points to thatOutstandingTokenrecord.
- Locate the corresponding
Implement custom JWT authentication
masterTo create a custom authentication mechanism that still utilizes JWT logic, inherit from
JWTBaseAuthentication. This is useful if you want to extract the token from a non-standard location, such as a specific API key header, while still performing JWT validation viaself.jwt_authenticate(request, token=key).from ninja.security import APIKeyHeader from ninja_jwt.authentication import JWTBaseAuthentication from ninja import router class ApiKey(APIKeyHeader, JWTBaseAuthentication): param_name = "X-API-Key" def authenticate(self, request, key): return self.jwt_authenticate(request, token=key) header_key = ApiKey() router = router('') @router.get("/headerkey", auth=header_key) def apikey(request): return f"Token = {request.auth}"Use Sliding tokens for authentication
masterSliding tokens provide a more convenient user experience by combining expiration and refresh capabilities. A sliding token remains valid for authentication as long as its expiration claim has not passed. It can also be submitted to a refresh view to receive a new token with a renewed expiration claim.
To implement sliding tokens, follow these two steps:
- Update
AUTH_TOKEN_CLASSESin your settings to include'ninja_jwt.tokens.SlidingToken'. - Register the
NinjaJWTSlidingControllerto your Ninja API.
Note on Performance: If you are using the
blacklistapp, Ninja JWT will validate every sliding token against the blacklist for every authenticated request, which may reduce performance.# 1. Update settings.py AUTH_TOKEN_CLASSES = ('ninja_jwt.tokens.SlidingToken',) # 2. Register the controller in your API setup from ninja_jwt.controller import NinjaJWTSlidingController from ninja_extra import NinjaExtraAPI api = NinjaExtraAPI() api.register_controllers(NinjaJWTSlidingController)- Update
Use Asynchronous Route Authentication
masterFor asynchronous endpoints, use the
AsyncJWTAuthclass.Requirements:
- The endpoint function must be defined with
async def. - Asynchronous features require Django version > 3.0.
from ninja_extra import api_controller, route from ninja_jwt.authentication import AsyncJWTAuth @api_controller class MyController: @route.get('/some-endpoint', auth=AsyncJWTAuth()) async def some_endpoint(self): ...- The endpoint function must be defined with
Enable the Ninja JWT token blacklist app
masterTo enable token blacklisting functionality, add
'ninja_jwt.token_blacklist'to yourINSTALLED_APPSin your Djangosettings.pyand run migrations.When enabled, Ninja JWT automatically tracks generated refresh or sliding tokens in an 'outstanding tokens' list and validates that refresh/sliding tokens are not present in the blacklist before considering them valid.
# Django project settings.py INSTALLED_APPS = ( ... 'ninja_jwt.token_blacklist', ... )Manually create tokens for a user
masterYou can manually generate new refresh and access tokens for a specific user by using the
RefreshToken.for_user(user)method. This is useful when you need to issue tokens outside of the standard authentication flow (e.g., during a custom login process or user registration).To get the usable string representations of the tokens, you must cast the
RefreshTokeninstance and itsaccess_tokenproperty tostr. This pattern works for any subclass ofninja_jwt.tokens.Token.from ninja_jwt.tokens import RefreshToken def get_tokens_for_user(user): # Create a new RefreshToken instance for the user refresh = RefreshToken.for_user(user) return { 'refresh': str(refresh), 'access': str(refresh.access_token), }Install django-ninja-jwt
masterInstall the package using pip. Ensure your environment meets the following requirements:
- Python >= 3.6
- Django >= 2.1
- Django-Ninja >= 0.16.1
- Django-Ninja-Extra >= 0.14.2
pip install django-ninja-jwtCustomize token claims via Controller Schema Swapping
masterStarting from v5.2.4, you can customize the claims included in web tokens without overriding controller functions. This is achieved by creating a custom input schema and registering it in the
NINJA_JWTsettings.Requirements
- Your custom input schema must inherit from
ninja_jwt.schema.TokenObtainInputSchemaBaseorninja_jwt.schema.TokenInputSchemaMixin. - You must override
get_token(cls, user)to define the dictionary of data (claims) to be returned. - You must override
get_response_schema()to return the schema used for the API response.
Implementation Steps
- Define your schemas in a module (e.g.,
project/schema.py):
from typing import Type, Dict from ninja_jwt.schema import TokenObtainInputSchemaBase from ninja.schema import Schema from ninja_jwt.tokens import RefreshToken class UserSchema(Schema): first_name: str email: str class MyTokenObtainPairOutSchema(Schema): refresh: str access: str user: UserSchema class MyTokenObtainPairInputSchema(TokenObtainInputSchemaBase): @classmethod def get_response_schema(cls) -> Type[Schema]: return MyTokenObtainPairOutSchema @classmethod def get_token(cls, user) -> Dict: values = {} refresh = RefreshToken.for_user(user) values["refresh"] = str(refresh) values["access"] = str(refresh.access_token) values.update(user=UserSchema.from_orm(user)) return values- Register the schema in your Django
settings.py:
NINJA_JWT = { 'TOKEN_OBTAIN_PAIR_INPUT_SCHEMA': 'project.schema.MyTokenObtainPairInputSchema', }# project/schema.py from typing import Type, Dict from ninja_jwt.schema import TokenObtainInputSchemaBase from ninja import Schema from ninja_jwt.tokens import RefreshToken class UserSchema(Schema): first_name: str email: str class MyTokenObtainPairOutSchema(Schema): refresh: str access: str user: UserSchema class MyTokenObtainPairInputSchema(TokenObtainInputSchemaBase): @classmethod def get_response_schema(cls) -> Type[Schema]: return MyTokenObtainPairOutSchema @classmethod def get_token(cls, user) -> Dict: values = {} refresh = RefreshToken.for_user(user) values["refresh"] = str(refresh) values["access"] = str(refresh.access_token) values.update(user=UserSchema.from_orm(user)) return values- Your custom input schema must inherit from
Configure Token Blacklisting
masterTo enable automatic blacklisting of refresh tokens after rotation:
- Set
'ROTATE_REFRESH_TOKENS': True. - Set
'BLACKLIST_AFTER_ROTATION': True. - Add
'ninja_jwt.token_blacklist'to your DjangoINSTALLED_APPS.
Note: This requires the blacklist app to be in use.
- Set
Authenticate routes using Function-Based Routers
masterWhen using standard Django Ninja routers, protect endpoints by passing an instance of
JWTAuth()to theauthparameter of the router method (e.g.,@router.get). The authenticated user will be available inrequest.userorrequest.auth.from ninja import router from ninja_jwt.authentication import JWTAuth router = router('') @router.get('/some-endpoint', auth=JWTAuth()) def some_endpoint(request): ...