Framework
jazzband/djangorestframework-simplejwt avatar
jazzband/djangorestframework-simplejwt

djangorestframework-simplejwt: token auth that plugs into DRF instead of replacing it

A JSON Web Token authentication plugin for the Django REST Framework.

4,334 stars709 forksPythonMIT

At a glance

What is it?
A JazzBand plugin that adds JSON Web Token authentication to the Django REST Framework, with a small dependency surface and an unusually honest changelog about migration mistakes.
Who is it for?
Simple JWT has held onto its shape for years: three runtime dependencies, one authentication backend, and a model layer that only exists if you opt into the token blacklist app. That narrowness is the reason it has 4,330 stars and 709 forks.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A deliberately small plugin with a very short README

The repository describes itself in one line: Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework. That is the whole scope. It does not replace DRF, it does not wrap it, and it does not ask you to change your views. It registers authentication classes that DRF already knows how to call.

The README is correspondingly short. It carries the Jazzband badge, CI and codecov badges, PyPI version and supported-Python badges, a Read the Docs badge, then an abstract and a pointer to the documentation site. The only other content is a translations section that invites pull requests and links to inlang as the translation editor.

That last detail is worth noting because it tells you something about the project's maintenance culture. Translations are handled through a hosted editor rather than a hand-managed locale directory, which means the maintenance burden of supporting many languages sits outside the repository.

The documentation site at django-rest-framework-simplejwt.readthedocs.io is where the install steps, the settings reference and the token lifecycle explanation live. The repository itself is MIT licensed, written in Python, and last pushed on 2026-09-21.

Three runtime dependencies tells you what the design bets on

The dependency list in `setup.py` is short enough to read as a design statement. Django, Django REST Framework, and PyJWT. Nothing else.

python
    install_requires=[
        "django>=4.2",
        "djangorestframework>=3.14",
        "pyjwt>=1.7.1",
    ],

There is no Redis dependency for a denylist, no cache library, no async HTTP client. Whatever token state the package keeps, it keeps in your database. The Python floor is 3.10 and Django's floor is 4.2, which puts the project in line with current long-term-support Django releases rather than older ones.

The cryptography story is handled through extras rather than required packages. The `crypto` extra asks for `cryptography>=3.3.1`, and there is a separate `python-jose` extra pinned to `python-jose==3.5.0`. The hard pin on that one is unusual and suggests the version has to be exact rather than merely compatible.

The development extras are far more elaborate than the runtime list, which is normal for a package with this many contributors. The `test` extra pulls in pytest along with pytest-django, pytest-cov, pytest-xdist, freezegun, tox and cryptography. Linting uses ruff, yesqa, pyupgrade and pre-commit. Typing uses mypy with django-stubs, djangorestframework-stubs and types-pytz. Documentation uses Sphinx with the Read the Docs theme. And the `dev` extra is deliberately built by concatenating all of those together with dev-only tools like pytest-watch, wheel, twine and ipython, which is a neat trick for avoiding a duplicated list.

How releases are versioned and published

Versions come from the tag rather than a hardcoded number. `setup.py` uses `setuptools_scm` with a post-release version scheme, so the released number is derived from git history at build time and written into the source tree during packaging.

The Makefile shows the release path a maintainer actually walks. Linting goes through a tox environment, tests run under pytest, and the documentation target runs `sphinx-apidoc` with an explicit list of paths to exclude from the API docs before building HTML and running doctests.

make
.PHONY: build-docs
build-docs:
	sphinx-apidoc -o docs/ . \
		setup.py \
		*confest* \
		tests/* \

That exclusion list is interesting on its own. It names `backends.py`, `exceptions.py`, `settings.py` and `state.py`, plus the whole `token_blacklist` subpackage. Those are the modules whose internals are documented by hand in the docs site rather than auto-generated, which tells you the hand-written prose is treated as the primary reference.

Publishing is a two-step local dance. The `dist` target cleans, builds both an sdist and a wheel, and lists the output directory. The `publish` target does the same build and then hands the result to twine.

make
.PHONY: publish
publish:
	python setup.py sdist bdist_wheel
	twine upload dist/*

Note the ordering implication: `dist` runs `clean` first, `publish` does not. A maintainer who runs `publish` straight after a build is uploading whatever is sitting in `dist/`, which is a small thing to know when reading a project's release habits.

Version 5.5.0 changed refresh behaviour and capped PyJWT

The release notes are unusually specific, and the interesting entries are the ones about behaviour rather than typing.

Version 5.5.0 shipped on 2025-02-26. Its most consequential change is a differing behaviour change: new refresh tokens are now added to the `OutstandingToken` database table. If you had assumed the blacklist app only stored tokens once they were revoked, that assumption is now wrong, and the table will grow with every refresh rather than every logout.

Three other entries in that release are about correctness under newer dependencies. PyJWT is capped below 2.10.0 to avoid an incompatibility with the subject claim type requirement, which is the kind of upper bound that surprises people during a dependency sweep. A fix landed for a user_id type mismatch when the user claim is not the primary key, and a separate change added specific token-expired exceptions so clients can distinguish expiry from other failures. The last change cached the signing key, which is a straightforward win since key parsing on every request is wasted work.

Version 5.4.0, released 2025-01-07, is where the inactive-user rules changed. One entry disables refresh tokens for inactive users, and a companion entry adds an option to allow inactive users to authenticate and generate tokens anyway. Those two pull in opposite directions on purpose, which means the default and the opt-in behave differently and you need to know which one you are on.

The same release also improved type inference for `BlacklistMixin` by making it generic, widened the return type of `Token.for_user` so subclasses type-check, and fixed a `Null` value in `OutstandingToken` when blacklisting.

The 5.5.1 patch is a story about a migration file

Version 5.5.1 came out on 2025-07-21, five months after 5.5.0, and it contains one fix: a previously missing migration for the token blacklist app. The release notes state plainly that the migration file was mistakenly not generated earlier, that it was never part of an official release, and that only people tracking the master branch would have hit the problem.

That candour is useful, because the migration it adds is numbered 0013 and there is a specific upgrade path for anyone who already has that row in their `django_migrations` table. The instructions are to roll the token_blacklist app back to migration 0012 first, upgrade the package, and then let the migrations run correctly so the state lines up.

Two things follow from that story. First, the recommended fix is to look at your `django_migrations` table before upgrading, which takes ten seconds and saves a bad afternoon. Second, a package whose primary artifact is a set of Django migrations has an unusual failure mode: the code can be correct while the database state is wrong, and no amount of testing on a fresh database will reproduce it.

The repository currently shows 4,330 stars, 709 forks and 160 open issues. That backlog is worth reading before you commit to the package in production, because the open questions tend to cluster around exactly the areas this article has flagged as non-obvious: blacklist growth, inactive users and refresh rules. The tree is conventional for a JazzBand package: the `rest_framework_simplejwt/` package with a `token_blacklist` subpackage, `tests/`, `docs/`, `scripts/`, a `licenses/` directory, `inlang.config.js`, `setup.cfg` alongside `setup.py`, `tox.ini`, `pytest.ini`, `codecov.yml` and a `CHANGELOG.md`.

Editorial conclusion

Simple JWT has held onto its shape for years: three runtime dependencies, one authentication backend, and a model layer that only exists if you opt into the token blacklist app. That narrowness is the reason it has 4,330 stars and 709 forks. The trade-off is equally real, since the README is three paragraphs long and everything you actually need lives in the Read the Docs site, so budget an hour reading the settings reference before you commit. Version 5.5.0 is the release to pay attention to if you are upgrading, because the PyJWT cap and the inactive-user refresh change both have migration implications, and 5.5.1 exists because of a missing migration file. If you want self-hosted JWT with a database record for every outstanding token, this is the package to start from. If you want stateless sessions and no blacklist tables at all, another library may fit better.

Frequently asked questions

What does djangorestframework-simplejwt do?

It is a JSON Web Token authentication plugin for the Django REST Framework, maintained under Jazzband and MIT licensed. It registers token-based authentication classes with DRF rather than replacing the framework, so your existing views, serializers and routers stay as they are.

What are the runtime dependencies?

`setup.py` lists three: django 4.2 or newer, djangorestframework 3.14 or newer, and pyjwt 1.7.1 or newer. Python 3.10 is the floor. Cryptography support is optional through the `crypto` extra, and there is a separate `python-jose` extra pinned to python-jose 3.5.0.

What changed in version 5.5.0?

New refresh tokens are now written to the OutstandingToken table, PyJWT is capped below 2.10.0 for subject-claim compatibility, specific token-expired exceptions were added, a user_id type mismatch was fixed when the user claim is not the primary key, and the signing key is now cached.

Why was version 5.5.1 released?

A migration numbered 0013 for the token blacklist app had been missing from earlier releases. It was only generated on the master branch, so the 5.5.1 release adds it. If you ran makemigrations in production against master, the release notes say to roll the token_blacklist app back to 0012 before upgrading.

Where is the real documentation?

The README is intentionally brief and points to django-rest-framework-simplejwt.readthedocs.io. The Makefile shows that modules such as settings, exceptions, backends and the token_blacklist package are deliberately excluded from generated API docs, so the hand-written pages on that site are the authoritative reference.

Official sources

  1. jazzband/djangorestframework-simplejwt on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jazzband-djangorestframework-simplejwt.svg)](https://hysenlabs.com/projects/jazzband-djangorestframework-simplejwt)