Skip to content

Authentication

Intro

Django Ninja provides several tools to help you deal with authentication and authorization easily, rapidly, in a standard way, without having to study and learn all the security specifications.

The core concept is that when you describe an api operation you can define an authentication object

from ninja import NinjaAPI
from ninja.security import django_auth

api = NinjaAPI(csrf=True)


@api.get("/pets", auth=django_auth)
def pets(request):
    return f"Authenticated user {request.auth}"

In this example client will be able to call the pets method only if it uses django session authentication (default is cookie based). Otherwise, a HTTP-401 error will be returned.

Automatic Openapi schema

Let's create an example where client in order to authenticate needs to pass a header :

Authorization: Bearer supersecret

from ninja.security import HttpBearer


class AuthBearer(HttpBearer):
    def authenticate(self, request, token):
        if token == "supersecret":
            return token


@api.get("/bearer", auth=AuthBearer())
def bearer(request):
    return {"token": request.auth}

Now go to docs at http://localhost:8000/api/docs:

Swagger UI Auth

When you click Authorize button you will get a prompt to input your authentication token

Swagger UI Auth

Now if you do test calls - the Authorization header will passed for every request.

Global authentication

In case you need to secure all methods of your api - you can pass auth argument to a NinjaAPI constructor:

from ninja import NinjaAPI, Form
from ninja.security import HttpBearer


class GlobalAuth(HttpBearer):
    def authenticate(self, request, token):
        if token == "supersecret":
            return token


api = NinjaAPI(auth=GlobalAuth())

# @api.get(...)
# def ...

# @api.post(...)
# def ...

And if you need to overrule some of those methods you can do that on the operation level again by passing the auth argument. In this example authentication will be disabled for /token operation:

from ninja import NinjaAPI, Form
from ninja.security import HttpBearer


class GlobalAuth(HttpBearer):
    def authenticate(self, request, token):
        if token == "supersecret":
            return token


api = NinjaAPI(auth=GlobalAuth())

# @api.get(...)
# def ...
# @api.post(...)
# def ...


@api.post("/token", auth=None)  # < overriding global auth
def get_token(request, username: str = Form(...), password: str = Form(...)):
    if username == "admin" and password == "giraffethinnknslong":
        return {"token": "supersecret"}

Available auth options

Custom function

The "auth=" argument accepts any Callable object. NinjaAPI passes authentication only if callable object returns a not None value. This return value will be assigned to request.auth attribute.

def ip_whitelist(request):
    if request.META["REMOTE_ADDR"] == "8.8.8.8":
        return "8.8.8.8"


@api.get("/ipwhiltelist", auth=ip_whitelist)
def ipwhiltelist(request):
    return f"Authenticated client, IP = {request.auth}"

API Key

Some APIs use API keys for authorization. An API key is a token that a client provides when making API calls. The key can be sent in the query string:

GET /something?api_key=abcdef12345

or as a request header:

GET /something HTTP/1.1
X-API-Key: abcdef12345

or as a cookie:

GET /something HTTP/1.1
Cookie: X-API-KEY=abcdef12345

Django Ninja comes with builtin classes to help you handle these cases.

in Query

from ninja.security import APIKeyQuery
from someapp.models import Client


class ApiKey(APIKeyQuery):
    param_name = "api_key"

    def authenticate(self, request, key):
        try:
            return Client.objects.get(key=key)
        except Client.DoesNotExist:
            pass


api_key = ApiKey()


@api.get("/apikey", auth=api_key)
def apikey(request):
    assert isinstance(request.auth, Client)
    return f"Hello {request.auth}"

In this example we take a token from GET['api_key'] and find a Client in database that corresponds to this key. The Client instance will be set to request.auth attribute

Note: param_name - is the name of GET parameter that will be checked for. If not set - default "key" will be used.

in Header

from ninja.security import APIKeyHeader


class ApiKey(APIKeyHeader):
    param_name = "X-API-Key"

    def authenticate(self, request, key):
        if key == "supersecret":
            return key


header_key = ApiKey()


@api.get("/headerkey", auth=header_key)
def apikey(request):
    return f"Token = {request.auth}"
from ninja.security import APIKeyCookie


class CookieKey(APIKeyCookie):
    def authenticate(self, request, key):
        if key == "supersecret":
            return key


cookie_key = CookieKey()


@api.get("/cookiekey", auth=cookie_key)
def apikey(request):
    return f"Token = {request.auth}"

HTTP Bearer

from ninja.security import HttpBearer


class AuthBearer(HttpBearer):
    def authenticate(self, request, token):
        if token == "supersecret":
            return token


@api.get("/bearer", auth=AuthBearer())
def bearer(request):
    return {"token": request.auth}

HTTP Basic Auth

from ninja.security import HttpBasicAuth


class BasicAuth(HttpBasicAuth):
    def authenticate(self, request, username, password):
        if username == "admin" and password == "secret":
            return username


@api.get("/basic", auth=BasicAuth())
def basic(request):
    return {"httpuser": request.auth}

Multiple authenticators

The auth argument allows also to pass multiple authenticators:

from ninja.security import APIKeyQuery, APIKeyHeader


class AuthCheck:
    def authenticate(self, request, key):
        if key == "supersecret":
            return key


class QueryKey(AuthCheck, APIKeyQuery):
    pass


class HeaderKey(AuthCheck, APIKeyHeader):
    pass


@api.get("/multiple", auth=[QueryKey(), HeaderKey()])
def multiple(request):
    return f"Token = {request.auth}"

In this case Django Ninja will first check the api key GET, and if not set or invalid will check the header key. And if both invalid will raise authentication error to response.