A proof of concept authentication module through JSON Web Tokens for G3W-SUITE.
Install jwt module into g3w-admin
applications folder:
# Install module from github (v1.0.0)
pip3 install git+https://github.com/g3w-suite/[email protected]
# Install module from github (master branch)
# pip3 install git+https://github.com/g3w-suite/g3w-admin-authjwt.git@master
# Install module from local folder (git development)
# pip3 install /g3w-admin/g3w-admin/authjwt
# Install module from PyPi (not yet available)
# pip3 install g3w-admin-authjwt
Enable 'authjwt'
module adding it to G3W_LOCAL_MORE_APPS
list:
# local_settings.py
G3WADMIN_LOCAL_MORE_APPS = [
...
'authjwt'
...
]
Refer to g3w-suite-docker repository for more info about running this on a docker instance.
NB On Ubuntu Jammy you could get an UNKNOWN
package install instead of g3w-admin-authjwt
, you can retry installing it as follows to fix it:
# Fix: https://github.com/pypa/setuptools/issues/3269#issuecomment-1254507377
export DEB_PYTHON_INSTALL_LAYOUT=deb_system
# And then install again the module
pip3 install ...
The following packages are included in this module:
Refer to the official docs for a more comprehensive list of the available settings:
# Customize Django CORS Headers (v3.11.0)
# -------------------------------------------
CORS_ALLOW_ALL_ORIGINS = True # NB: DEVELOPMENT ONLY!
CORS_ALLOWED_ORIGINS = [ # NB: DIFFERENT PORT == DIFFERENT SERVER
'http://localhost:8080',
'http://localhost:8081',
'http://127.0.0.1:8080',
'http://127.0.0.1:8081',
]
# Customize Django REST Framework - Simple JWT (v5.2.2)
# -------------------------------------------
from datetime import timedelta
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_EXPIRATION_DELTA': timedelta(hours=1),
'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=7), #
}
# NB: longer-lived tokens can reduce HTTP traffic
# but they also highlight "health check" issues after
# user logout (given the stateless nature of JWT requests,
# if not handled for example through a "token blacklist",
# the user could still appear as logged-in even after a logout)
# See also:
# - https://django-rest-framework-simplejwt.readthedocs.io/en/latest/blacklist_app.html
# - https://django-rest-framework-simplejwt.readthedocs.io/en/latest/stateless_user_authentication.html
For the default settings currently applied by this module, see also: authjwt/__init__.py
Check the authjwt/apiurls.py
file for a comprehensive list and how to use them.
Find out that they are loaded correctly in your project by running the following command in a terminal shell:
python3 manage.py show_urls
/authjwt/api/ rest_framework.routers.APIRootView api-root
/authjwt/api/\.<format>/ rest_framework.routers.APIRootView api-root
/authjwt/api/ping/ authjwt.views.PingViewSet ping-list
/authjwt/api/ping\.<format>/ authjwt.views.PingViewSet ping-list
/authjwt/api/token/ rest_framework_simplejwt.views.TokenObtainPairView token_obtain_pair
/authjwt/api/token/blacklist/ rest_framework_simplejwt.views.TokenBlacklistView token_blacklist
/authjwt/api/token/refresh/ rest_framework_simplejwt.views.TokenRefreshView token_refresh
/authjwt/api/token/verify/ rest_framework_simplejwt.views.TokenVerifyView token_verify
Tip: if you are developing locally use a software like httpie (or postman) to import and save the following curl commands for later use:
curl --request POST \
--url http://localhost:8000/authjwt/api/token/ \
--header 'Content-Type: application/json' \
--data '{ "username":"admin", "password":"admin" }'
curl --request POST \
--url http://localhost:8000/authjwt/api/token/refresh/ \
--header 'Content-Type: application/json' \
--data '{ "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY3MTI2NTIyNiwiaWF0IjoxNjcxMTc4ODI2LCJqdGkiOiI3OGFiODU2MjcyZWM0YjAxOWI1Y2M4NTA1ZmNiMTIwOSIsInVzZXJfaWQiOjJ9.AAKmj8I3IN936PrOcxqGmsImWVkFk2AtsFJSE_o4dlY" }'
curl --request POST \
--url http://localhost:8000/authjwt/api/token/verify/ \
--header 'Content-Type: application/json' \
--data '{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY3MTI3NTg4NSwiaWF0IjoxNjcxMTg5NDg1LCJqdGkiOiIxMTk2NWNiNGFkYjE0ZmEzOTUxYzBhOTkxNDlhZWMwNyIsInVzZXJfaWQiOjJ9.YA4MesWfQcbYip6EhRxZoQAFxoZeBdlJdCrEme8sTc0" }'
curl --request GET \
--url 'http://localhost:8000/authjwt/api/ping/?id=pong' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjcxMTgyNDIxLCJpYXQiOjE2NzExODIxMjEsImp0aSI6IjI5YjQyN2ZlYjRkMjQ3YmM4NDAzODcyY2VhOTM2NWI5IiwidXNlcl9pZCI6Mn0.P6E7r9BCEFMzkTohJR4EMW1m8wm4DGZ03232mJO6vQI'
curl --request POST \
--url http://localhost:8000/authjwt/api/token/blacklist/ \
--header 'Content-Type: application/json' \
--data '{ "refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY3MTI3NTg4NSwiaWF0IjoxNjcxMTg5NDg1LCJqdGkiOiIxMTk2NWNiNGFkYjE0ZmEzOTUxYzBhOTkxNDlhZWMwNyIsInVzZXJfaWQiOjJ9.YA4MesWfQcbYip6EhRxZoQAFxoZeBdlJdCrEme8sTc0" }'
Steps to follow for local development of this module.
Traditional workflow
Steps to follow in case of a regular install.
Clone and place the g3w-admin-authjwt
repository into g3w-admin
applications folder:
cd /path/to/your/development/workspace
git clone https://github.com/g3w-suite/g3w-admin.git ./g3w-admin
git clone https://github.com/g3w-suite/g3w-admin-authjwt.git ./g3w-admin/g3w-admin/authjwt
So your folder structure should matches the following:
.
└── g3w-admin/
├── g3w-admin/
│ ├── authjwt/
│ │ ├── authjwt/
│ │ │ ├── __init__.py
│ │ │ ├── apps.py
│ │ │ ├── urls.py
│ │ │ ├── views.py
│ │ │ └── ...
│ │ ├── pyproject.toml
│ │ └── README.md
│ ├── base/
│ ├── core/
│ ├── ...
│ └── manage.py
└── README.md
Install the g3w-admin-authjwt
module from the local source folder:
pip3 install /g3w-admin/g3w-admin/authjwt
Then activate the 'authjwt'
module as usual by adding it to G3W_LOCAL_MORE_APPS
list.
Alternative workflow
Steps to follow in case of a editable install.
Clone g3w-admin
and g3w-admin-authjwt
repositories into two adjacent folders:
cd /path/to/your/development/workspace
git clone https://github.com/g3w-suite/g3w-admin.git
git clone https://github.com/g3w-suite/g3w-admin-authjwt.git
So your folder structure should matches the following:
.
├── g3w-admin/
│ ├── g3w-admin/
│ │ ├── base/
│ │ ├── core/
│ │ ├── ...
│ │ └── manage.py
│ └── README.md
│
└── g3w-admin-authjwt/
├── authjwt/
│ ├── __init__.py
│ ├── apps.py
│ ├── urls.py
│ ├── views.py
│ └── ...
├── pyproject.toml
└── README.md
Install the g3w-admin-authjwt
module in editable mode starting from your g3w-admin
folder:
cd g3w-admin
python3 -m pip install -e ../g3w-admin-authjwt
Then activate the 'authjwt'
module as usual by adding it to G3W_LOCAL_MORE_APPS
list.
Create a new git tag
that is appropriate for the version you intend to publish, eg:
git tag -a v1.0.1
git push origin v1.0.1
Publishing on the Python Package Index
Steps to follow when releasing a new software version on PyPi.
First make sure you have the latest versions of pip
, build
and twine
installed:
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade build
python3 -m pip install --upgrade twine
Build the dist
folder starting from the same directory where pyproject.toml
is located:
python3 -m build
Upload all to PyPI and verify things look right:
twine upload dist/*
Find out if it could be feasible to code a sort of proxy class for the rest_framework.permissions.IsAuthenticated
(or for the rest_framework.viewsets
) in order to make use of JWT Authentication with legacy API endpoints that make use of the django.contrib.auth.decorators.login_required
method to check if a user is authenticated, ie:
# apiurls.py
from django.contrib.auth.decorators import login_required
...
urlpatterns = [
path(
'api/some-protected-view/',
login_required(SomeProtectedView.as_view()), # currently "SomeProtectedView" doesn't support JWT Auth
name='some-protected-view'
)
]
Code samples on how to implement JWT with Vue and Django Rest Framework:
Sample project on how to develop a complete docker stack (backend + frontend):
Sample project on how to implement a "simplejwt" extension without using the Django Rest Framework:
Packaging a Python project:
- PyPA walkthrough
src
layout vsflat
layout- Configuring
setuptools
- Configuring
setuptools-scm
- Using
twine
- Automate publishing of Python Packages with GitHub Actions
License: MPL-2