Simple JWT
Abstract
Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework.
For full documentation, visit django-rest-framework-simplejwt.readthedocs.io.
Looking for Maintainers
For more information, see here.
Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework.
For full documentation, visit django-rest-framework-simplejwt.readthedocs.io.
For more information, see here.
Hey folks! So Simple JWT has really come a ways in terms of popularity (further than I probably would have imagined). For that, I owe a big "Thank you!" to the community of Django and REST devs that have used and contributed to the project!
However, for a while now I haven't had a lot of time to devote to addressing issues and feature requests. My professional life dominates my schedule and it also hasn't tended to involve much REST API development in recent years. But the library continues to enjoy widespread use. Contributors request/develop features and identify usability/security issues on a daily basis. I don't have enough time in my personal schedule to serve all of the community's needs! But I want to see the project continue to succeed.
For that reason, I'm interested in hearing from any devs that wish to become involved in maintaining this project. I'm particularly interested in hearing from devs who have contributed to this project in the past and/or who can demonstrate experience with similar engineering projects. Significant histories of open source contribution are obviously a plus! If you're located in Boulder, CO (which is in the US), that's also a huge plus. We could potentially meet in person to get acquainted.
Please reply to this issue if you think you match the above criteria! I'm looking forward to hearing from all of you!
This issue tracks the implementation of the Jazzband guidelines for the project django-rest-framework-simplejwt
It was initiated by @davesque who was automatically assigned in addition to the Jazzband roadies.
See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.
Feel free to ping a Jazzband roadie if you have any question.
README
fileCONTRIBUTING.md
or CONTRIBUTING.rst
filejazzband
account to PyPI project as maintainer role (e.g. URL: https://pypi.org/manage/project/django-rest-framework-simplejwt/collaboration/)jazzband-bot
as maintainer to the Read the Docs project (e.g. URL: https://readthedocs.org/dashboard/django-rest-framework-simplejwt/users/)Description | A JSON Web Token authentication plugin for the Django REST Framework. |
Homepage | https://django-rest-framework-simplejwt.readthedocs.io/ |
Stargazers | 2236 |
Open issues | 81 |
Forks | 351 |
Default branch | master |
Is a fork | False |
Has Wiki | True |
Has Pages | False |
Hi all! Due to the sheer number of requests and urges for #157 to be merged, I have created a template repository with a Django server ready-to-go. To generate a sample repository for SimpleJWT, please press the "Use this template" button so that you don't fork the repository; this way, you can rename the repository to whatever name you want (although please follow naming conventions of the React and Vue.js repos already setup. It'd be great if you could also transfer ownership to the SimpleJWT organization so that everyone knows about it -- i.e. viewable -- and can be maintained by the community).
The template repository: https://github.com/SimpleJWT/drf-SimpleJWT-server-template
Currently created repositories:
In the future:
There are other frontend frameworks like Angular (JS), Flutter (Dart), Ember (JS), etc. If I didn't create them, it just means I undervalue them (jk). I just don't want to get ahead of myself. If you want to contribute and you're using one of these frameworks, by all means @Andrew-Chen-Wang (i.e. mention me) in this issue, and I will create a repository for you.
To reiterate, you will need unittest cases. For those who want the #157 merger, at least two frontend frameworks that are used on web browsers must be completed and tested to have the PR to be considered for merger. Not only that, it must use the PR's latest commit (do not use master branch; specify a commit SHA). I cannot stress this enough: security is number one priority. To publish a package with, imo, still a highly insecure PR since there is still no one who has given me a single test repository, SimpleJWT would be doomed in vulnerabilities and CVEs.
So.... Thanks for contributing Djangonauts!
enhancement help wantedHey– I'm trying to get this package integrated and I'm getting something odd here when a jwt is being created. Is anyone else running into this issue? I'm on 4.4.0
AttributeError: 'str' object has no attribute 'decode'.
File "/.../.venv/lib/python3.7/site-packages/rest_framework_simplejwt/tokens.py", line 226, in for_user
token=str(token),
File "/.../.venv/lib/python3.7/site-packages/rest_framework_simplejwt/tokens.py", line 82, in __str__
return token_backend.encode(self.payload)
File "/.../.venv/lib/python3.7/site-packages/rest_framework_simplejwt/backends.py", line 43, in encode
return token.decode('utf-8')
AttributeError: 'str' object has no attribute 'decode'
bug
Hi and thanks in advance,
I've successfully setup JWT authentication using django-rest-framework-simplejwt and React but I'm still very confused about the advantages and specifically database hits.
I'm using simplejwt with ROTATE_REFRESH_TOKENS': True 'BLACKLIST_AFTER_ROTATION': True
, when my access_token expire I ask for a new one through /api/token/refresh and it blacklist old tokens, I'm using axios interceptors to perform that automatically.
But in my understanding the benefits of JWt is that they are stateless, meaning I don't have to hit the user database table everytime I want to make an a request that needs authentication permission. The problem is even with a simple view like this :
class IsConnecteddAPI(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request, *args, **kwargs):
data = "You seem to be connected"
return Response(data, status=status.HTTP_200_OK)
using django-silk I see that it still performs 1 query to my user table when my access token is valid , is that normal ? I'm really confused.
Here are django silk outputs screen1 screen2 screen3 screen4
Isn't get_user from https://github.com/SimpleJWT/django-rest-framework-simplejwt/blob/master/rest_framework_simplejwt/authentication.py hiting the user object everytime ?
I've already asked the question on reddit and SO and they advised me to remove AuthMiddleware, so I removed both 'django.middleware.csrf.CsrfViewMiddleware'
and 'django.contrib.auth.middleware.AuthenticationMiddleware'
but I still get the same result. Setting permissions_classes to AllowAny doesn't vhange anything either.
That's my axios code if needed :
import axios from "axios";
const baseURL = "http://localhost:5000";
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
Authorization: localStorage.getItem("accesstoken")
? "JWT " + localStorage.getItem("accesstoken")
: null,
"Content-Type": "application/json",
accept: "application/json",
},
});
const axioAnonymousInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
if (typeof error.response === "undefined") {
alert(
"A server/network error occurred. " +
"Looks like CORS might be the problem. " +
"Sorry about this - we will get it fixed shortly."
);
return Promise.reject(error);
}
if (
error.response.status === 401 &&
originalRequest.url === baseURL + "token/refresh/"
) {
window.location.href = "/login/";
return Promise.reject(error);
}
if (
error.response.data.code === "token_not_valid" &&
error.response.status === 401 &&
error.response.statusText === "Unauthorized"
) {
const refreshToken = localStorage.getItem("refreshtoken");
if (refreshToken) {
const tokenParts = JSON.parse(atob(refreshToken.split(".")[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
if (tokenParts.exp > now) {
return axioAnonymousInstance
.post("/api/token/refresh/", { refresh: refreshToken })
.then((response) => {
localStorage.setItem("accesstoken", response.data.access);
localStorage.setItem("refreshtoken", response.data.refresh);
axiosInstance.defaults.headers["Authorization"] =
"JWT " + response.data.access;
originalRequest.headers["Authorization"] =
"JWT " + response.data.access;
return axiosInstance(originalRequest);
})
.catch((err) => {
// redirect ro /login here if wanted
console.log("axios Safe Instance error");
console.log(err);
// window.location.href = "/login/";
});
} else {
console.log("Refresh token is expired", tokenParts.exp, now);
window.location.href = "/login/";
}
} else {
console.log("Refresh token not available.");
window.location.href = "/login/";
}
}
// specific error handling done elsewhere
return Promise.reject(error);
}
);
export { axiosInstance, axioAnonymousInstance };
( I know I shouldn't use localStorage but whatever )
and I would typically just call this function to make the simple request to the view written above :
const IsConnected = () => {
axiosInstance
.get("/api/is_connected/")
.then((response) => {
if (response.status === 200) {
console.log(response.data);
console.log("Is connected : CONNECTED ");
} else {
console.log("IS connected : not connected");
}
})
.catch((error) => {
console.log("Is connected : NOT CONNECTED");
console.log(error);
});
};
question
Could a new release be pushed to PyPI that includes #186?
For users using Django 3.0, django-rest-framework-simplejwt
currently throws a warning. If running unit tests with -Werror
, this causes builds to failed unless the warning is suppressed.
Recently the PyJWT package has been updated and is throwing this error when generating a token.
PyJWT latest version: https://github.com/jpadilla/pyjwt/releases/tag/2.0.0
The exception is raised in:
rest_framework_simplejwt/backends.py in encode at line 43
just in return token.decode('utf-8')
line
I have solved it by explicitly putting the PyJWT package in my requirements.txt file, just below djangorestframework-simplejwt
version that introduces the error:
PyJWT==2.0.0
downgraded version to make it work:
PyJWT==v1.7.1
class TokenObtainSerializer(serializers.Serializer):
username_field = User.USERNAME_FIELD
def __init__(self, *args, **kwargs):
super(TokenObtainSerializer, self).__init__(*args, **kwargs)
self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField()
def validate(self, attrs):
self.user = authenticate(**{
self.username_field: attrs[self.username_field],
'password': attrs['password'],
})
if self.user is None or not self.user.is_active:
raise serializers.ValidationError(
_('No active account found with the given credentials'),
)
return {}
TokenObtainSerializer is using authenticate function which makes it impossible use something else than User.USERNAME_FIELD for authentication.
Let's say I set username_field
to something else than User.USERNAME_FIELD
, for example email
(and assume User.USERNAME_FIELD
equals to username
). Is this going to work? authenticate
function is going to use User.USERNAME_FIELD
= username
but serializer has received email
field.
Hello! Awesome library, keep up the good work!
I encountered a bug in the latest release which boils down to the following lines https://github.com/jazzband/djangorestframework-simplejwt/blob/4d7c7649813f9eae4bd28ed17da685cd3a61f2fe/rest_framework_simplejwt/serializers.py#L141-L151
File "/home/user/.cache/pypoetry/virtualenvs/MSWA2ZbW-py3.8/lib/python3.8/site-packages/rest_framework/serializers.py", line 436, in run_validation
value = self.validate(value)
File "/home/user/.cache/pypoetry/virtualenvs/MSWA2ZbW-py3.8/lib/python3.8/site-packages/rest_framework_simplejwt/serializers.py", line 150, in validate
if BlacklistedToken.objects.filter(token__jti=jti).exists():
AttributeError: type object 'BlacklistedToken' has no attribute 'objects'
I think whats happening here is that since I don't have the blacklisted app in my installed apps as I dont require it, the BlacklistedToken
model is being set as abstract=True
and since we aren't specifically checking the presence of the app in the above lines, this error happened
So I've been trying to build a Django project that handles authentication centrally on a standalone basis using django-rest-framework-simplejwt
. And other Django Rest Framework projects that use this for authentication. All projects will have their own databases.
I am not quite sure what goes into the database section in settings.py of both the auth project and other projects. The documentation mentions something about JWTTokenUserAuthentication
backend as an experimental feature and is quite inadequate.
I have done some research and found I may have to use a remote user login or set up a proxy server. Can someone point me in the right direction?
questionHi, I'm trying to use a custom User model/extension of the default Django auth.User model in my application.
I created the User and Manager like so:
import uuid
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUserManager(BaseUserManager):
def create_user(self, email, company_name, password=None):
if not email:
raise ValueError("User must have an email address.")
if not company_name:
raise ValueError("User must have a company name.")
user = self.model(email=self.normalize_email(email),
company_name=company_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, company_name, password):
user = self.create_user(email=self.normalize_email(email),
company_name=company_name,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
username = None
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
company_name = models.CharField(max_length=30)
# The following fields are required for every custom User model
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['company_name']
objects = CustomUserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_superuser
def has_module_perms(self, app_label):
return True
but when I create users of this model and try to login into my app with them instead of getting a JWT token like before I get a message stating that there are no active users with those credentials...
How can I use SimpleJWT with a custom User model?
Thanks
questionIn https://github.com/jazzband/djangorestframework-simplejwt/pull/521 serializer classes used by the view of this app was made configurable, however there is no documentation regarding this except than relase notes.
This should also be documented.
File "./rest_framework_simplejwt/state.py", line 1, in <module>
from .backends import TokenBackend
File "./rest_framework_simplejwt/backends.py", line 7, in <module>
from jwt import InvalidAlgorithmError, InvalidTokenError, algorithms
File "./jwt/algorithms.py", line 5, in <module>
from .exceptions import InvalidKeyError
ImportError: cannot import name 'InvalidKeyError' from 'jwt.exceptions' (./site-packages/jwt/exceptions.py)
Django==4.1.3 jwt==1.3 pyjwt==2.6.0 djangorestframework-simplejwt==5.2.2 downgrade to => djangorestframework-simplejwt==4.7.2 then problem fixed
When you use the token_blacklist
app to revoke tokens, the app stores the full refresh tokens in plain text in the DB. Which seems like a security risk if a DB gets leaked. Even a django Admin can impersonate a user by simply copying their token.
I'm not sure why this is needed, can't we use jti
claim to revoke generated tokens? this would require us to decode the token before verifying it to look up the JTI_CLAIM
in the BlacklistedToken
Model objects. but it'd be safer. Similar to how django-rest-knox
stores hashed tokens to protect against DB leaks.
I'm new to the library but I can attempt to draft a PR if the idea itself is approved.
Thanks.
I'm using simplejwt to implement a RP using Auth0 as an IDP, so simplejwt is only used to decode and verify RS256 signed JWTs generated by Auth0. The value of SIGNING_KEY in this configuration should be irrelevant.
The Django Rest Framework docs describe how the authentication classes behave and their return values. They describe describe request.auth as:
The request.auth property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with. ... The authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set request.user and request.auth using the return value of the first class that successfully authenticates.
Developers relying on request.auth for debugging may assume it is safe to call str(request.auth)
because it is in copy-pastable form in the django-rest-framework Authentication docs.
However, rest_framework_simplejwt.authentication.Token.__str__
calls TokenBackend.encode()
which assumes SIGNING_KEY is set to a key appropriate for the algorithm configuration. If SIGNING_KEY is unset, the key is derived from SECRET_KEY, which is not compatible with RS256:
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [_OpenSSLErrorWithText(code=503841036, lib=60, reason=524556, reason_text=b'error:1E08010C:DECODER routines::unsupported')])
Or, if SIGNING_KEY is set to None:
TypeError: Expecting a PEM-formatted key
In addition to the poor developer experience, this also creates a path for a vulnerability where a naive call to str() could generate signed JWTs when the developer's intention was only consume them.
Proposal:
Token.__str__
should raise an exception indicating that simplejwt is configured in verification-only mode.Token.__str__
should raise an exception indicating that the token is not safe for serialization.I'm doing this project where I use a jwt as auth for the user; however, the access token never expire even thou it is equal to 1min in the settings.py, but when I issue a new access token within the minute it works, but after a minute it shouldn't work and the view should return a 403 code, but this is not what happining and the view return the data even after one or two days or the expiration time for the token.
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=1),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': False,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=1),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
Full Changelog: https://github.com/jazzband/djangorestframework-simplejwt/compare/v5.2.0...v5.2.1
Source code(tar.gz)Full Changelog: https://github.com/jazzband/djangorestframework-simplejwt/compare/v5.1.0...v5.2.0
Source code(tar.gz)Meta:
Translations:
Source code(tar.gz)Full Changelog: https://github.com/jazzband/djangorestframework-simplejwt/compare/v4.8.0...v5.0.0
Source code(tar.gz)https://github.com/jazzband/djangorestframework-simplejwt/blob/master/CHANGELOG.md#version-472
Source code(tar.gz)Dj-Rest-Auth Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well with SPAs (e.g React, Vue, Ang
JSON:API and Django REST framework Overview JSON:API support for Django REST framework Documentation: https://django-rest-framework-json-api.readthedo
django-rest-knox Authentication Module for django rest auth Knox provides easy to use authentication for Django REST Framework The aim is to allow for
djoser REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such
DRF Docs Document Web APIs made with Django Rest Framework. View Demo Contributors Wanted: Do you like this project? Using it? Let's make it better! S
App de Usuários Esse é um app de usuários personalizado feito em Django REST Framework, nele eu modifiquei o model padrão de users do Django, adiciona
django-rest-localflavor Country-specific serializers fields, to Django Rest Framework Documentation (soon) The full documentation is at https://django
?? Fast, Async-ready, Openapi, type hints based framework for building APIs
drf-yasg - Yet another Swagger generator Generate real Swagger/OpenAPI 2.0 specifications from a Django Rest Framework API. Compatible with Django Res
Introduction to Django Rest Framework This is the repository of the video series Introduction to Django Rest Framework published on YouTube. It is a s
Django REST Framework extensions DRF-extensions is a collection of custom extensions for Django REST Framework Full documentation for project is avail
DRF Generators Writing APIs can be boring and repetitive work. Don't write another CRUDdy view in Django Rest Framework. With DRF Generators, one simp
Django REST Swagger: deprecated (2019-06-04) This project is no longer being maintained. Please consider drf-yasg as an alternative/successor. I haven
djangorestframework-recursive Overview Recursive Serialization for Django REST framework This package provides a RecursiveField that enables you to se
drf-dropdown Dropdown population implementation for Django REST Framework Usage Add DropdownView to API URL # urls.py import dropdown urlpatterns = [
Django Rest API django-rest-framework Employees management simple API in this project wrote test suites for endpoints wrote simple doc string for clas
SIMPLE CRUD API WITH DJANGO REST FRAMEWORK Django REST framework is a powerful and flexible toolkit for building Web APIs. Requirements Python 3.6 Dja
BloodDonors By Daniel Yuan, Alex Tian, Aaron Pan, Jennifer Yuan As the pandemic raged, one of the side effects was an urgent shortage of blood donatio
Built on Django Rest Framework, to provide with command execution on linux terminal