Package: django-ninja-simple-jwt
django-ninja-simple-jwtProvides simple JWT based stateless authentication for Django-ninjaQuick startInstall package:pip install django-ninja-simple-jwtaddninja_simple_jwtto list ofINSTALLED_APPSin Django settings:# settings.pyINSTALLED_APPS=[...,"ninja_simple_jwt"]ExposeDjango-ninja's API and addninja_simple_jwt's auth API endpoint router to the API, ie:# urls.pyfromninjaimportNinjaAPIfromninja_simple_jwt.auth.views.apiimportmobile_auth_router,web_auth_routerfromdjango.urlsimportpathapi=NinjaAPI()api.add_router("/auth/mobile/",mobile_auth_router)api.add_router("/auth/web/",web_auth_router)urlpatterns=[path("api/",api.urls)]This would provide 4 available auth API endpoints for mobile and web sign in and token refresh:{{server_url}}/api/auth/mobile/sign-in{{server_url}}/api/auth/mobile/token-refresh{{server_url}}/api/auth/web/sign-in{{server_url}}/api/auth/web/token-refreshIf you are not exposing the API and routers at the exact path as the example above,
seeWEB_REFRESH_COOKIE_PATHsetting regarding web auth token refresh path.To protect a resource API, you can use theHttpJwtAuthas the auth argument when instantiating a Router, ie:# views.pyfromninja_simple_jwt.auth.ninja_authimportHttpJwtAuthfromninjaimportRoutersome_resource_router=Router(auth=HttpJwtAuth())@some_resource_router.get("/hello")defhello(request):return"Hello world"Finally, before starting up the server, create a key pair to be used by the server for signing and verifying JWT:python manage.py make_rsaYou should see two files created in the root of project repository:jwt-signing.pem  # this is the private key used to sign a JWT, keep this secret, store appropriatelyjwt-signing.pub  # this is the public key used to verify a JWTDocumentationCustomizing JWT key storageBy default, the management commandmake_rsawill create and store the JWT key pairs in the root of your project
directory, this is only intended for development.Here is an example how you can store the keys in a S3 bucket somewhere only your application has access to, assuming
you are usingdjango-storagesto access AWS S3.# some_project_dir/my_jwt_key_storage.pyfromstorages.backends.s3boto3importS3Boto3Storageaws_s3_private_key_storage=S3Boto3Storage(bucket_name="MySecretJwtKeysStorage")aws_s3_public_key_storage=S3Boto3Storage(bucket_name="MyPublicJwtKeysStorage")and provide the above storage instances in Django settings:# settings.pyNINJA_SIMPLE_JWT={"JWT_PRIVATE_KEY_STORAGE":"some_project_dir.my_jwt_key_storage.aws_s3_private_key_storage","JWT_PUBLIC_KEY_STORAGE":"some_project_dir.my_jwt_key_storage.aws_s3_public_key_storage",...}You can provide any custom storage implementation in this setting provided that they follow Django's Storage API.You should make sure that the private key storage is only accessible by the auth service application.
The public key storage may be made accessible by other services that need to verify the JWT issued by the auth service.Enabling auth API endpointsMobileYou can enable the mobile auth end points by adding a provided router to the ninja API class:# urls.pyfromninjaimportNinjaAPIfromninja_simple_jwt.auth.views.apiimportmobile_auth_routerfromdjango.urlsimportpathapi=NinjaAPI()api.add_router("/auth/mobile/",mobile_auth_router)urlpatterns=[path("api/",api.urls)]In the above example with themobile_auth_router, you would gain the following endpoints:/api/auth/mobile/sign-incurl --location 'http://127.0.0.1:8000/api/auth/mobile/sign-in' \
--header 'Content-Type: application/json' \
--data '{
    "username": "my-username",
    "password": "my-password"
}'The response would contain refresh and access JWT in the body:{"refresh":"...","access":"..."}/api/auth/mobile/token-refreshcurl --location 'http://127.0.0.1:8000/api/auth/mobile/token-refresh' \
--header 'Content-Type: application/json' \
--data '{
    "refresh": "..."
}'The response would contain an access JWT in the body:{"access":"..."}WebSee also:web auth endpoint design.Similarly to the Mobile auth end point example above,
you can enable the web auth endpoints by adding it to the ninja API class:# urls.pyfromninjaimportNinjaAPIfromninja_simple_jwt.auth.views.apiimportweb_auth_routerfromdjango.urlsimportpathapi=NinjaAPI()api.add_router("/auth/web/",web_auth_router)urlpatterns=[path("api/",api.urls)]You would gain the following endpoints:/api/auth/web/sign-incurl --location 'http://127.0.0.1:8000/api/auth/web/sign-in' \
--header 'Content-Type: application/json' \
--data '{
    "username": "my-username",
    "password": "my-password"
}'The response would contain the access JWT in the body, however the refresh JWT is only in a cookie:refresh=...; expires=Fri, 09 Feb 2024 03:49:33 GMT; HttpOnly; Max-Age=2591999; Path=/api/auth/web/token-refresh; SameSite=StrictBy default, this refresh cookie is only used when calling the token refresh endpoint (below)./api/auth/web/token-refreshcurl --location --request POST 'http://127.0.0.1:8000/api/auth/web/token-refresh' \
--header 'Cookie: refresh=...'The response would contain an access token in the body.Customizing token claims for userYou can specify a claim on the JWT and what User model attribute to get the claim value from using the
settingTOKEN_CLAIM_USER_ATTRIBUTE_MAP.
By default, this setting has the following value:{# claim: model attribute"user_id":"id","username":"username","last_login":"last_login",}Serializing user attribute into JWT claimIf the model attribute is not by default serializeable, you can specify how to serialize it by providing a custom
implementation of json encoder class. Ie:# some_directory/custom_encoders.pyfromninja_simple_jwt.jwt.json_encodeimportTokenUserEncoderclassCustomTokenUserEncoder(TokenUserEncoder):defdefault(self,o:Any)->Any:ifisinstance(o,SomeCustomClass):returnself.serialize_some_custom_class(o)returnsuper().default(o)defserialize_some_custom_class(self,o:SomeCustomClass)->str:# custom serialization implementation herereturn"serialized value"And then provide the import string for this class in Django setting:# settings.pyNINJA_SIMPLE_JWT={...,"TOKEN_USER_ENCODER_CLS":"some_directory.custom_encoders.CustomTokenUserEncoder"}SettingsAll settings specific for this library are stored as key-value pairs under Django settingNINJA_SIMPLE_JWT, ie:# settings.pyNINJA_SIMPLE_JWT={...}Seelist of all available settings.