Django Ninja

Django OAuth Toolkit provides a support layer for Django Ninja.

This consists of a HttpOAuth2 class, which will determine whether the incoming HTTP request contains a valid OAuth2 access token issued by Django OAuth Toolkit. Optionally, HttpOAuth2 can ensure that the OAuth2 Access Token contains a defined set of scopes.

Import HttpOAuth2 as:

from oauth2_provider.contrib.ninja import HttpOAuth2

Basic Usage

HttpOAuth2 can be used anywhere that Django Ninja expects an authentication callable.

For example, to ensure all requests are authenticated with OAuth2:

from ninja import NinjaAPI
from oauth2_provider.contrib.ninja import HttpOAuth2

api = NinjaAPI(auth=HttpOAuth2())

To require authentication on only a single endpoint:

from ninja import NinjaAPI
from oauth2_provider.contrib.ninja import HttpOAuth2

api = NinjaAPI()

@api.get("/private", auth=HttpOAuth2())
def private_endpoint(request):
    return {"message": "This is a private endpoint"}

Optional Authentication

HttpOAuth2 will always fail if the request is not authenticated. However, many use cases require optional authentication (for example, where additional private content is returned for authenticated users).

Django Ninja’s support for multiple authenticators can be used for optional authentication. Simply place HttpOAuth2 at the beginning of a list of authenticators (where it will be run first), with more permissive authenticator functions near the end (as a fall-back).

For example, to attempt OAuth2 authentication on all requests, but allow access even for unauthenticated requests:

from ninja import NinjaAPI
from oauth2_provider.contrib.ninja import HttpOAuth2

# Stricter authenticators must be placed first,
# as the first success terminates the chain
api = NinjaAPI(auth=[HttpOAuth2(), lambda _request: True])

Scope Enforcement

HttpOAuth2 can optionally enforce that the OAuth2 access token has certain scopes (defined by the application).

If a scopes argument is passed to HttpOAuth2, then incoming access tokens must contain all of the specified scopes to be considered valid.

For example:

from ninja import NinjaAPI
from oauth2_provider.contrib.ninja import HttpOAuth2

api = NinjaAPI()

@api.post("/thing", auth=HttpOAuth2(scopes=["read", "write"]))
def create_endpoint(request):
    ...

Custom Authorization Behavior

HttpOAuth2 can be extended to provide custom authorization behaviors.

Simply subclass it and override its authenticate method.

class oauth2_provider.contrib.ninja.HttpOAuth2(*args: Any, **kwargs: Any)

Perform OAuth2 authentication, for use with Django Ninja.

authenticate(request: HttpRequest, access_token: AbstractAccessToken) Any | None

Determine whether authentication succeeds.

If this returns a truthy value, authentication will succeed. Django Ninja will set the return value as request.auth.

Subclasses may override this to implement additional authorization logic.

For example:

from typing import Any

from django.http import HttpRequest
from ninja import NinjaAPI
from oauth2_provider.contrib.ninja import HttpOAuth2
from oauth2_provider.models import AbstractAccessToken

class StaffOnlyOAuth2(HttpOAuth2):
    def authenticate(self, request: HttpRequest, access_token: AbstractAccessToken) -> Any | None:
        if not access_token.user.is_staff:
            return None

        # Anything truthy can be returned, and will be available as `request.auth`
        return access_token

api = NinjaAPI(auth=StaffOnlyOAuth2())