Setup

① Add authentication, login and 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"),
    ...
]

② Configure settings with the JWT_EMAIL_AUTH key. Here is a minimal config (some values are defaults):

JWT_EMAIL_AUTH = {
    "SENDING_ON": True,  # needs to be set explicitly!
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=14),
    "LOGIN_CODE_LIFETIME": timedelta(minutes=5),
    "EXPECTED_CLAIMS": ["foo", "bar"],
    "CACHE_PREFIX": "PREFIX",
    "LOGIN_ATTEMPTS": 10,
    "LOGIN_COOLDOWN": timedelta(minutes=5),
    "CODE_SEND_COOLDOWN": timedelta(minutes=1),
    "LOGIN_VALIDATION_AND_DATA_CALLBACK": "path.to.module.function",
}

Here are the rest of the settings and what they mean.

Setting Description Type
SENDING_ON Whether emails
should be sent or not.
When off, login code is
logged instead
(for development).
bool
SKIP_CODE_CHECKS When True, any
code will work in login.
bool
SKIP_CODE_CHECKS_FOR List of emails for
which code checks and
email sending are off, even
if SKIP_CODE_CHECKS=False
and/or SENDING_ON=True.
Useful for creating review
accounts in an otherwise
closed system.
list[str]
ACCESS_TOKEN_LIFETIME How long an access
token is valid for.
timedelta
REFRESH_TOKEN_LIFETIME How long a refresh
token is valid for.
timedelta
LOGIN_CODE_LIFETIME How long a login
code is stored in cache.
timedelta
LOGIN_COOLDOWN After user has
exceeded defined number
of login attemprs,
this is the cooldown
until they can attempt
login again.
timedelta
CODE_SEND_COOLDOWN After a user has
sent a login code,
this is the cooldown
until they can send
one again.
timedelta
NOT_BEFORE_TIME How long after the
creation of the
JWT does it
become valid.
timedelta
ROTATE_REFRESH_TOKENS If True, return a
new refresh token
when requesting a new
access token from
RefreshTokenView. The old
refresh token will be invalid
after the new one is created.
bool
LOGIN_ATTEMPTS Number of login
attempts until user
is banned.
int
EXPECTED_CLAIMS List of expected JWT
content.
list[str]
UPDATEABLE_CLAIMS Which expected claims
can be updated without
re-authentication using
the update view.
list[str]
LOGIN_SENDING_EMAIL Email sender. str
LOGIN_SUBJECT_LINE Email subject line. str
LOGIN_EMAIL_MESSAGE Message to send in
email. Must have
{code} and {valid}!
str
LOGIN_EMAIL_HTML_TEMPLATE Path to html_message
template. Context
must have {{ code }}
and {{ valid }}!
Path
CACHE_PREFIX Cache prefix. str
OPTIONS_SCHEMA_ACCESS When True (default),
OPTIONS requests can
be made to the endpoint
without token for schema
access.
bool
CIPHER_KEY If set, JWT will be
encrypted with AES in
GCM-mode using this as
the secret key. Should be
either 16, 24, or 32 bytes,
encoded to base64.
str
ISSUER Issuer of the JWT. str
AUDIENCE Intended recipient
of the JWT.
str
LEEWAY A time margin in
seconds for the
expiration check.
int
ALGORITHM Algorithm to sign
and decrypt the
token with.
str
HEADER_PREFIX Authorization scheme
used in Authorization header,
as in HEADER_PREFIX token.
str
EXTRA_HEADERS Additional JWT header
fields.
dict[str, str]

These settings should be specified in "dot import notation" to a function, which will be imported as the value for the setting.

Setting Description Arguments Returns
SIGNING_KEY Function to load
JWT signing key.
?
CODE_GENERATOR Function to generate
a login code.
str
SEND_LOGIN_CODE_CALLBACK Function that sends
the login email.
str,
dict[str, Any],
Request
None
LOGIN_VALIDATION_AND_DATA_CALLBACK Function to use for
validating user and providing
login data.
str dict[str, Any]
LOGIN_BLOCKER_CACHE_KEY_CALLBACK Function to generate
cache key for storing user's
login attempts.
Request str
USER_BLOCKED_ADDITIONAL_HANDLER Function for additional
handling for blocked users.
Request None
USER_CHECK_CALLBACK Function to check if token
user still exists in
refresh view.
RefreshToken None

IP address spoofing prevention settings:

Setting Description Type
PROXY_ORDER Indicate whether the
originating client is on
the right or left in the
X-Forwarded-For header
"left-most"
"right-most"
PROXY_COUNT Number of proxies between
the server and internet.
int
PROXY_TRUSTED_IPS Only these proxy IPs
are allowed connections
List[str]
REQUEST_HEADER_ORDER Meta precedence order. List[str]

Settings when using cookies:

Setting Description Type
USE_TOKENS If True, can authenticate
with tokens in Authorization
header. Set this to False and
USE_COOKIES to True to only
allow cookie authentication.
bool
USE_COOKIES If True, can authenticate
with tokens in HttpOnly
headers. Cookies will be
checked before Authorization
headers if they are
enabled.
bool
DEFAULT_LOGIN_METHOD Default login method
to use if none is given in
Prefer-headers. If not set,
cookie-based login will be
used if enabled,
else token-based.
ACCESS_TOKEN_KEY Cookie key to use
for the access token
str
REFRESH_TOKEN_KEY Cookie key to use
for the refresh token
str
SET_COOKIE_SECURE Indicates that the
cookie is sent to the server
only when a request is
made with the https: scheme
(except on localhost) and
therefore, is more resistant to
man-in-the-middle attacks.
bool
SET_COOKIE_ACCESS_PATH Indicates the path
that must exist in the requested
URL for the browser
to send the access token cookie.
str
SET_COOKIE_REFRESH_PATH Indicates the path
that must exist in the requested
URL for the browser
to send the refresh token cookie.
str
SET_COOKIE_DOMAIN Defines the host to
which the cookie will be sent.
If None, this attribute
defaults to the host of the
current document URL, not
including subdomains.
str
SET_COOKIE_HTTPONLY If True, forbids JavaScript
from accessing the cookie.
bool
SET_COOKIE_SAMESITE Controls whether a cookie
is sent with cross-origin
requests, providing some
protection against cross-site
request forgery attacks (CSRF).
"lax"
"strict"
"none"

③ Add OpenSSH based ed25519 SIGNING_KEY (in PEM format) to environment variables. You can create one with, e.g., ssh-keygen using the command ssh-keygen -t ed25519. The linebreaks in PEM format should be replaced with | (pipe) characters. If you do not want to use environment variables, override the SIGNING_KEY setting.

A default signing key is provided for reference in the settings-module, but this should be changed in production environments.

④ Configure Django's email settings (if using django's email sending):

# 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 = ...

⑤ (Optional) Add default authentication_classes or permission_classes:

REST_FRAMEWORK = {
    ...
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "jwt_email_auth.authentication.JWTAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "jwt_email_auth.permissions.HasValidJWT",
    ]
    ...
}