djoser: WebAuthn needs an extra, and the non-uv install names an extra that does not exist
REST implementation of Django authentication system.
At a glance
- What is it?
- A Django REST Framework view set for registration, login, password reset and activation, whose four advertised features rest on four hard runtime dependencies, one optional extra, and two different mechanisms for holding development requirements.
- Who is it for?
- djoser fits projects that want registration, login, logout, password reset and activation as API endpoints against a custom user model, and it is the deliberate reimplementation of Django's own auth forms, which is both the reason it works with a single page app and the reason fixes upstream will not reach it. Verify three things before depending on it.
- 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 65 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 5, 2026, and from our analysis. They are not legal advice.
Editorial analysis
WebAuthn is advertised beside three features that install by default
The supported features are given as a flat list of four: token-based authentication, JWT authentication, social authentication, and WebAuthn support. Only three of those are present after the documented install. The project metadata puts webauthn under optional dependencies as `webauthn<1.0`, so WebAuthn is an extra, while the three others come from the required dependency list. The install command in the project overview is a single line and does not name extras, which means a team that reads the feature list, installs the package, and expects passkey registration to work gets a missing dependency rather than a message about a feature flag. Nothing in the prose marks WebAuthn as conditional. The other three features are not optional either, and not through extras: simplejwt and social auth app django are required dependencies with upper bounds, so the JWT and social support described as features are pulled in by every install whether or not a project touches them. The list also does not say how any of the four are selected. Nothing in the feature list points at the extras mechanism, and token authentication is named in no extra at all, so four peer capabilities appear where the install tree holds three unconditional dependencies and one opt in. A team that skips the extra and then meets a missing module gets no hint from the feature list that packaging was the decision.
The requirements section names three dependencies and the package installs four
The stated requirements are Python, Django, and Django REST Framework, one line each. The required dependency list is longer. Alongside django>=3.2 and djangorestframework>=3.14 it carries djangorestframework-simplejwt with a floor of 5.0 and a ceiling below 6.0, and social-auth-app-django with a floor of 5.0.0 and a ceiling below 6.0.0. Neither appears in the requirements prose, and neither is an extra, so a project that only wants token authentication still resolves a JWT library and a social auth provider. The two ceilings are the notable part, because they are narrower than anything in the Django requirement. The prose gives the Django range as 3.2 through 5.2 and the dependency gives an open ended floor, so the version spread that matters for compatibility is not the one a reader is shown at install time. The token feature named first in the feature list is the only one with no third party dependency behind it. The overview names two similar projects, django-rest-registration and django-oauth-toolkit, and puts that list after the feature bullets without saying what either does differently, so the comparison a reader would want, whether token creation validation behaves the same way, is left open. The metadata adds a classifier block running from Framework :: Django through seven numbered Django versions.
The Python ceiling appears in prose and not in the metadata
The project overview states the requirement as Python>=3.9,<4.0 and then names 3.10, 3.11, 3.12, and 3.13 as included. The package metadata says `requires-python = ">=3.9"`, with no upper bound at all. So the ceiling that rules out a future major Python release exists only as a sentence, while the field a package index reads when resolving dependencies has no ceiling. The same split runs through Django: the prose says Django>=3.2 supporting 3.2 through 5.2, the dependency says django>=3.2, and the classifiers enumerate 3.2, 4.0, 4.1, 4.2, 5.0, 5.1, and 5.2. The classifier list matches the sentence, so the tested range is documented twice, while the resolved range is open at the top in both the Python field and the Django dependency. Version 2.3.4 is written into the metadata as a static value, not derived from a tag, so the version a resolver reports comes from that line. The rest of the classifier block is short: Intended Audience :: Developers, Operating System :: OS Independent, and License :: OSI Approved :: MIT License. The license is written as a text field rather than a license expression, and a LICENSE file sits at the root beside a CREDITS file, so the licensing story is stated three times and consistently.
The install path without uv names a test extra the metadata does not define
There are two ways to get a development environment, and they disagree about where the development requirements live. The uv path runs `uv sync --all-extras --all-groups`, which pulls in both extras and every dependency group. The path headed without uv runs a different command.
$ pip install .[test]
$ cd testproject
$ ./manage.py testThe extra named there is test, and the metadata does not define it as a project extra. Under project optional dependencies there is exactly one entry, webauthn. The test requirements instead sit under a dependency groups table, and the comment above that table says they live in PEP 735 groups precisely so they are not published as extras in the wheel metadata, with installation called for as uv sync with a group name. So the documented pip command asks for an extra that the package metadata does not define, while the requirements it is meant to install are in a table the same metadata keeps out of the extras namespace on purpose. A comment in that file also notes that dev dependencies are not published as extras, which is the same distinction stated once more.
The documented test command and the make target are not the same test
Three entry points run tests and none of them match. The uv path in the project overview says `uv run pytest testproject/`. The Makefile target behind `make test` runs `uv run py.test --capture=no --cov-report term-missing --cov-report html --cov=djoser testproject/` and then a second line producing coverage xml. The fall back path calls `./manage.py test` from inside the testproject directory, which is Django's own runner rather than pytest. The difference between the first two is not cosmetic: the Makefile suppresses output capture and turns on coverage over the djoser package with both a terminal report and an HTML report, so a developer following the prose instead of the Makefile gets a run that neither measures coverage nor behaves the same way under failure. The repository carries both pytest.ini and .coveragerc at the root, so the coverage configuration exists for the Makefile path. Two more files at the root bear on how a change reaches a release. .pre-commit-config.yaml is installed into the local repository with `uv run pre-commit install`, and the overview names what it runs: Black for formatting, Ruff for linting, Docformatter for docstrings, and other quality checks it does not enumerate. An .isort.cfg is tracked at the root as well, even though the named hooks already cover formatting and linting with Black and Ruff. Anyone reading the short command in the overview is not running the command the project uses on itself.
Eight phony targets exist and four appear in the project overview
The Makefile declares init, build, test, migrate, runserver, run-hooks, docs, and update-deps as phony. The overview shows four of them, init, test, migrate, and runserver, and describes the first two in prose before showing the commands. That leaves four targets a reader of the overview never hears about. The build target is the one with a consequence: it compiles message catalogs before packaging, running pybabel with the django domain against the djoser/locale directory and then uv build. So the artifact is assembled after a localization step rather than straight from the source tree, and a plain build of the package that skips that compile is not the same artifact. The update-deps target upgrades the lock file and resynchronises, and the docs target syncs a docs group with an inexact flag before recursing into the docs directory to build html through Sphinx. None of the three is mentioned outside the Makefile. The docs target also points at machinery that is tracked: a .readthedocs.yml at the root and a docs directory, matching the second place the overview says documentation lives, since it names both the hosted site and the docs directory. That makes three documentation surfaces to keep in step, the hosted build, the repository directory, and the project overview, which carries its own installation and development instructions.
A deliberate None from authenticate() can be ignored
The last paragraph of the project overview is the most useful thing in it. It says that when custom authentication and TokenCreateSerializer validation are used, there is a path that ignores an intentional return of None from authenticate() and tries to find a user by parameters instead. In practice a backend that returns None to signal that it does not handle a request can have that decision overridden, and the lookup continues as though the credentials had been accepted. The closing sentence offers no date and no version for a fix. That paragraph sits after a list of two similar projects, so the caveat is easy to reach past, and it is the only place the file acknowledges a behavioural gap rather than a feature. It is also the one paragraph that describes what the library does wrong, which makes it the first thing to read if a project is wiring a non-default authentication backend into token creation.
The auth forms are reimplemented rather than reused from Django
The overview is explicit that djoser does not reuse Django's own code, naming PasswordResetForm as an example, and says the pieces were reimplemented to fit a single page app architecture better. That is the design decision everything else follows from. Views for registration, login, logout, password reset, and account activation come from Django REST Framework, the library works with a custom user model, and the forms behind those views are the project's own. The trade is explicit maintenance: a fix applied to Django's form does not arrive here, and the project carries its own message catalogs under a locale directory, compiled during the build. The project describes itself as community-maintained, asks contributors to follow the Lightbend Community Code of Conduct, and records one maintainer by name and address in the metadata. The classifier set marks the package as a production stable release, and the repository tracks a .claude directory alongside a Makefile, a release notes file, and a changelog. The root also carries CHANGELOG.rst, RELEASE.md, and CREDITS.rst, so the release procedure is a file a reader can consult rather than a process described in the overview. The repository tracks testproject/ as a Django project used by both the pytest path and the manage.py path, and djoser/ as the package itself, which is also the coverage target named in the Makefile.
Editorial conclusion
djoser fits projects that want registration, login, logout, password reset and activation as API endpoints against a custom user model, and it is the deliberate reimplementation of Django's own auth forms, which is both the reason it works with a single page app and the reason fixes upstream will not reach it. Verify three things before depending on it. WebAuthn is advertised beside token, JWT and social auth but ships as the optional extra webauthn, so the documented install command does not install the fourth feature. The documented fall back for working without uv names a test extra that the package metadata defines as a dependency group instead, so that path needs checking. And the custom authentication caveat at the end of the project overview is a real behavioural gap: a deliberate None from authenticate() can be ignored while the user is looked up by parameters, with no date attached to a fix. Teams wanting session cookie auth or Django's own views should stay on Django.
Frequently asked questions
how to install djoser
The project overview gives one command, pip install djoser, and then points at the configuration guide in the online documentation. The stated requirements are Python>=3.9, Django>=3.2, and Django REST Framework>=3.14. Development setup is separate, using uv with a sync of all extras and all groups, or pip with pyproject.toml, and there is a Makefile with init and test targets.
what is djoser in django
A set of Django REST Framework views for registration, login, logout, password reset, and account activation, working with a custom user model. It supports token, JWT, social, and WebAuthn authentication, and reimplemented pieces such as Django's own PasswordResetForm rather than reusing them, so the forms fit a single page app architecture.
Which Python and Django versions does djoser support?
The overview states Python>=3.9,<4.0 with 3.10 through 3.13 named, and Django>=3.2 supporting 3.2 through 5.2, which matches the classifier list. The metadata itself is looser: requires-python is written as >=3.9 with no ceiling, and the dependency is django>=3.2 with no upper bound, so the resolved range is open at the top.
Do I need an extra for djoser's WebAuthn support?
Yes. WebAuthn is the one feature listed as optional, declared under project optional dependencies as webauthn with a ceiling below 1.0. The install command in the overview installs the base package without extras, so that fourth advertised feature needs the extra installed separately.
How do I run the djoser test suite?
With uv, run pytest against the testproject directory, or use the Makefile targets init and test, where the test target adds coverage reporting over the djoser package. Without uv, the overview shows installing the package with a test extra and then running manage.py test from the testproject directory.
What does djoser do about Django's own auth forms?
It reimplements pieces of them, naming PasswordResetForm as an example, rather than reusing Django's code, in order to fit a single page app architecture. The library works with a custom user model, and it keeps its own message catalogs, which the build target compiles from a locale directory.
Official sources
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.
[](https://hysenlabs.com/projects/sunscrapers-djoser)