JWT authentication from email login codes.
Project description
JSON Web Token Email Authentiation
pip install jwt-email-auth
This module enables JSON Web Token Authentication in Django Rest framework without using Django's User model. Instead, login information is stored in cache, sent to the user's inbox, and obtained using a code that was sent to the given email.
Requirements:
Setup
- Add
jwt_email_auth
to Django's installed apps.
INSTALLED_APPS = [
...
"jwt_email_auth",
...
]
- Add authentication, login, and token refresh views to urlpatterns.
from django.urls import path
from jwt_email_auth.views import SendLoginCodeView, LoginView, RefreshTokenView
urlpatterns = [
...
path("authentication/", SendLoginCodeView.as_view(), name="authentication"),
path("login/", LoginView.as_view(), name="login"),
path("refresh/", RefreshTokenView.as_view(), name="refresh"),
...
]
# Or use routers...
# --------------------------------------------------------------------------------
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from jwt_email_auth.views import SendLoginCodeView, LoginView, RefreshTokenView
router = DefaultRouter()
router.register(r"authentication", SendLoginCodeView, "authentication")
router.register(r"login", LoginView, "login")
router.register(r"refresh", RefreshTokenView, "refresh")
urlpatterns = [
...
path("", include(router.urls)),
...
]
- Configure JWT email auth settings.
JWT_EMAIL_AUTH = {
# Required:
#
# Off by default, will log message instead if False.
"SEND_EMAILS": True,
# A path to a function, in dot import notation,
# that returns what should be stored in cache before login
# codes are sent. This data is then added to the JWT claims
# when the login is successful. Note that 'code' is reserved
# for the login code that the login is made with, and it's not
# added to JWT claims during login.
"LOGIN_DATA": "path.to.function",
# Other useful ones:
#
# Skip login code checks, for development.
"SKIP_CODE_CHECKS": True,
# How long tokens are valid. By default, access tokens
# are valid for 5 minutes, and refresh tokens for 14 days.
"ACCESS_TOKEN_LIFETIME": timedelta(...),
"REFRESH_TOKEN_LIFETIME": timedelta(...),
# How long login codes are valid in cache (5 minutes by default).
"LOGIN_CODE_LIFETIME": timedelta(...),
# Path to an alternative code generator function, in dot import notation.
"CODE_GENERATOR": "path.to.function",
# The message to send. Should contain '{code}' and '{valid}' which will be
# replaced by the login code and valid time in minutes.
"LOGIN_EMAIL_MESSAGE": "...",
# Path to login HTML template. Context for this will include two values,
# 'code' (code needed for login) and 'valid' (code valid time in minutes).
"LOGIN_EMAIL_HTML_TEMPLATE": "templates/example_login.html",
# List of extra claims that token validation expects to find inside the token.
# If not all of these are found, token is deemed invalid. Off by default.
"EXPECTED_CLAIMS": [...],
# How many times login can be attemted before used is banned
# for a short while (10 by default).
"LOGIN_ATTEMPTS": 10,
# How long user needs to wait from last login attempt until login
# ban is lifted (5 minutes by default)
"LOGIN_COOLDOWN": timedelta(...),
}
Have a look at the provided settings for more.
- Configure Django's email email settings.
# Not all of these may be required
EMAIL_HOST_USER = ...
EMAIL_HOST_PASSWORD = ...
EMAIL_HOST = ...
EMAIL_PORT = ...
EMAIL_USE_TLS = ...
EMAIL_USE_SSL = ...
EMAIL_BACKEND = ...
EMAIL_SENDER = ...
EMAIL_SUBJECT_PREFIX = ...
DEFAULT_FROM_EMAIL = ...
SERVER_EMAIL = ...
- Add OpenSSH based ed25519
SIGNING_KEY
(in PEM format) to environment variables. You can create one with, e.g., ssh-keygen using the commandssh-keygen -t ed25519
. The linebreaks in PEM format should be replaced with | (pipe) characters. If you do not want to use environment variables, override theSIGNING_KEY
setting.
A default signing key is provided for reference, but this should obviously be changed in production environments.
- (Optional) Add custom authentication classes to Rest framework settings.
REST_FRAMEWORK = {
...
"DEFAULT_AUTHENTICATION_CLASSES": [
...
"jwt_email_auth.authentication.JWTAuthentication",
...
],
"DEFAULT_PERMISSION_CLASSES": [
...
"jwt_email_auth.permissions.HasValidJWT",
...
]
...
}
Usage
- Send a login code to the authentication endpoint (from SendLoginCodeView class).
Request | Response |
---|---|
POST [Authentication URI] Content-Type: application/json |
HTTP 204 NO CONTENT |
{ "email":"person@example.com" } |
... |
- POST the login code and email to login endpoint (from LoginView class).
Request | Response |
---|---|
POST [Login URI] Content-Type: application/json |
HTTP 204 ACCEPTED |
{ "email":"person@example.com" "code":"123222" } |
{ "access":"..." "refresh":"..." } |
- Refresh access token from the refresh token endpoint (from RefreshTokenView class).
Request | Response |
---|---|
POST [Refresh Token URI] Content-Type: application/json |
HTTP 200 OK |
{ "token":"..." } |
{ "access":"..." } |
Authentication and Permission classes
Add the JWTAuthentication or HasValidJWT to Rest framework's settings or or to the classe's authentication or permission classes
from rest_framework.views import APIView
from jwt_email_auth.authentication import JWTAuthentication
from jwt_email_auth.permissions import HasValidJWT
class SomeView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [HasValidJWT]
...
Base Access Serializer
If you need to use claims from the token in you code, you can use the BaseAccessSerializer.
from rest_framework.views import APIView
from rest_framework.authentication import get_authorization_header
from jwt_email_auth.serializers import BaseAccessSerializer
class SomeSerializer(BaseAccessSerializer):
take_form_token = ["example", "values"]
...
class SomeView(APIView):
def post(self, request, *args, **kwargs):
prefix, encoded_token = get_authorization_header(request).split()
serializer = SomeSerializer(data={"token": encoded_token})
serializer.is_valid(raise_exception=True)
data = serializer.validated_data # use .validated_data and not .data!
print(data) # {"example": ..., "values": ...}
...
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for jwt_email_auth-0.0.4-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9f54b005b3acc893889fd048afd17d1ddde293adaa65c75b3edd8f2fbcaa6eb3 |
|
MD5 | b585e352d68096b881f16f76b341763c |
|
BLAKE2b-256 | ad37353b1ce8eda1f611c40c2875f67c8f5867772dde7c3d4c086e9522fc3bf1 |