Published at

Django Ninja JWT Integration Guide

Django Ninja JWT Integration Guide

Integrate Django Ninja JWT for secure API authentication. Learn to install, configure, and use JWT endpoints with custom controllers and localization.

Authors
  • avatar
    Name
    James Lau
    Twitter
  • Indie App Developer at Self-employed
Sharing is caring!
Table of Contents

This blog post guides you on integrating Django Ninja JWT into your Django Ninja project for robust authentication.

Installation

First, install the django-ninja-jwt package using pip:

pip install django-ninja-jwt

Configuration

  1. Register the Controller:

In your api.py file, register the NinjaJWTDefaultController to enable the default JWT endpoints.

from ninja_jwt.controller import NinjaJWTDefaultController
from ninja_extra import NinjaExtraAPI

api = NinjaExtraAPI()
api.register_controllers(NinjaJWTDefaultController)
  1. Custom Controllers (Optional):

You can create custom controllers inheriting from TokenObtainPairController to manage token retrieval and refresh.

from ninja_extra import api_controller
from ninja_jwt.controller import TokenObtainPairController

@api_controller('token', tags=['Auth'])
class MyCustomController(TokenObtainPairController):
    """obtain_token and refresh_token only"""
    ...
api.register_controllers(MyCustomController)

This example creates a controller under the “token” path, allowing you to customize authentication logic while leveraging the built-in JWT functionality.

  1. Localization (Optional):

To enable translations, add ninja_jwt to your INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    ...
    'ninja_jwt',
    ...
]

Usage Examples

Here’s how to interact with the JWT endpoints using curl.

  1. Obtain Token Pair:

This request retrieves both an access token and a refresh token. Replace `

curl -X POST http://your-api-url/token/obtain/ \
  -H "Content-Type: application/json" \
  -d '{"username": "your_username", "password": "your_password"}'

The response will include an access token (short-lived, used for authenticated requests) and a refresh token (long-lived, used to obtain new access tokens):

{
    "access": "your_access_token",
    "refresh": "your_refresh_token"
}
  1. Refresh Token:

To obtain a new access token using the refresh token:

curl -X POST http://your-api-url/token/refresh/ \
  -H "Content-Type: application/json" \
  -d '{"refresh": "your_refresh_token"}'

The response will provide a new access token:

{
    "access": "new_access_token"
}
  1. Using the Access Token:

Use the access token to authenticate API requests by including it in the Authorization header:

curl -X GET http://your-api-url/protected-endpoint/ \
  -H "Authorization: Bearer your_access_token"

Customizing Authentication Logic

You can extend the TokenObtainPairController to add custom validation or additional fields to the token response. For example:

from ninja import Schema
from ninja_jwt.controller import TokenObtainPairController
from ninja_extra import api_controller, route

class CustomTokenResponse(Schema):
    access: str
    refresh: str
    user_id: int

@api_controller('token', tags=['Auth'])
class MyCustomController(TokenObtainPairController):
    @route.post("/obtain", response=CustomTokenResponse)
    def obtain_token(self, request, *args, **kwargs):
        response = super().obtain_token(request, *args, **kwargs)
        return {
            "access": response["access"],
            "refresh": response["refresh"],
            "user_id": request.user.id
        }

This custom controller adds the user_id to the token response, which can be useful for client-side applications.

Securing Endpoints

To protect your API endpoints, use the api.auth decorator or middleware provided by Django Ninja. For example:

from ninja import Router
from ninja_jwt.authentication import JWTAuth

router = Router(auth=JWTAuth())

@router.get("/protected")
def protected_endpoint(request):
    return {"message": f"Hello, {request.user.username}!"}

This ensures only requests with a valid access token can access the endpoint.

Best Practices

  • Token Expiry: Configure token lifetimes in settings.py to balance security and usability. For example:
JWT_AUTH = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
}
  • HTTPS: Always use HTTPS in production to secure token transmission.
  • Refresh Token Rotation: Enable refresh token rotation to enhance security by invalidating old refresh tokens upon use.
  • Error Handling: Implement proper error handling for invalid tokens or unauthorized access to provide clear feedback to clients.

Troubleshooting

  • Invalid Token Errors: Ensure the token is correctly included in the Authorization header as Bearer <token>.
  • Localization Issues: Verify that ninja_jwt is in INSTALLED_APPS and that translation files are correctly configured.
  • Custom Controller Errors: Double-check that your custom controller is registered with the API and that the paths are correct.

Conclusion

Integrating Django Ninja JWT into your project provides a secure and flexible way to handle API authentication. By leveraging default or custom controllers, you can tailor the authentication flow to your needs while supporting localization for a global audience. Follow the best practices outlined above to ensure a robust and secure implementation.

For more details, check the official Django Ninja JWT documentation or explore the Django Ninja and PyJWT libraries for advanced configurations.

Sharing is caring!