Generate JWTs with Django

2,521 views
Skip to first unread message

Claude Paroz

unread,
Apr 15, 2020, 3:09:30 PM4/15/20
to Django developers (Contributions to Django itself)
Hi all,

With the recent addition of the algorithm parameter to the signing.Signer class, it's now rather straightforward for Django to generate HS256 (non-encrypted) JSON Web Tokens.
With a growing popularity of JS-client/Django server communications (DRF and al.), I think there might be some interest for Django to be able to generate and decode such tokens. For any other types of JWTs which generally require access to a cryptography module, we can point users to third-party libs like PyJWT (the docs should be clear about that).

I made a proof-of-concept PR (docs missing) here:
 - https://github.com/django/django/pull/12728

What people here think about that proposal?

Claude

Abhijeet Viswa

unread,
Apr 15, 2020, 3:14:18 PM4/15/20
to django-d...@googlegroups.com
Hi,

You might want check out django-restframework-simplejwt. It requires the Django Rest Framework. But, then again, if you are making an API, you'd already be using it.

Regards,
Abhijeet

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5f67fefb-d158-4722-b704-6c34d72692a8%40googlegroups.com.

Claude Paroz

unread,
Apr 15, 2020, 3:27:17 PM4/15/20
to django-d...@googlegroups.com
Thanks Abhijeet for the pointer, I know there are some rather complete
JWT libs around, but my proposal is not about a complete package to
manage JWT in general.
It's rather some low level ability for Django to produce and decode
simple HS256 JWT. Then other third-party libs could build on that
ability to write more elaborate packages.

The main doubt I have about my proposal is whether HS256 JWTs are too
limited for most usages or in the contrary if they are appropriate for a
fair amount of use cases.

Claude

Le 15.04.20 à 21:13, Abhijeet Viswa a écrit :
> Hi,
>
> You might want check out django-restframework-simplejwt. It requires the
> Django Rest Framework. But, then again, if you are making an API, you'd
> already be using it.
>
> Regards,
> Abhijeet
>
> On Thu, 16 Apr, 2020, 00:39 Claude Paroz, <cla...@2xlibre.net

Claude Paroz

unread,
Apr 22, 2020, 4:57:36 AM4/22/20
to django-d...@googlegroups.com
For your information, I now added docs to the tentative patch:

https://github.com/django/django/pull/12728

Claude

Le 15.04.20 à 21:26, Claude Paroz a écrit :

Adam Johnson

unread,
Apr 22, 2020, 9:39:20 AM4/22/20
to django-d...@googlegroups.com
Hi Claude

JWT's are indeed popular for API's. I think if Django was being created "from the ground up" today, JWT's would be a no-brainer to include, so it seems reasonable to add some support.

I've had a look at the PR, and yes it is indeed a small amount of code - and thanks for the documentation.

Have you got any data on how often encrypted vs. non-encrypted JWT's are used? Personally I can't remember from the projects I've worked on which format has been used.

Thanks,

Adam

--
You received this message because you are subscribed to the Google Groups "Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

Markus Holtermann

unread,
Apr 24, 2020, 10:32:27 AM4/24/20
to Django developers
Nice work, Claude!

However, dealing with JWTs, and especially verifying them is notoriously hard and fragile. Frankly, I think I'd rather see smaller libraries do one job and do it well, than having Django implement an incomplete JWT spec. As far as I can tell, only HS256 signing/verification is implemented, but nothing else, right?

Cheers,

Markus
> > To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com <mailto:django-developers%2Bunsu...@googlegroups.com>.
> > To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/87ddf575-0756-b99e-51d8-99de1b258c21%402xlibre.net.
>
>
> --
> Adam
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-develop...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/CAMyDDM2x%3D%2BB0xM0YRauHxwDDm2ymxeGmYqYCVdOMJS94-F4Xdg%40mail.gmail.com <https://groups.google.com/d/msgid/django-developers/CAMyDDM2x%3D%2BB0xM0YRauHxwDDm2ymxeGmYqYCVdOMJS94-F4Xdg%40mail.gmail.com?utm_medium=email&utm_source=footer>.

Claude Paroz

unread,
Apr 24, 2020, 1:08:32 PM4/24/20
to Django developers (Contributions to Django itself)
Hey Markus,

In fact, when I had to implement that in one of my projects, I realized that Django has already most tools needed to (in my opinion) properly handle those tokens. And indeed, this only covers HS256-type of JWTs, for any other type, we would recommend using a third-party package (see the docs type of my patch).
If we had to reimplement all the hard work of signing and verifying, I would not have proposed this addition to Django.

Claude

James Bennett

unread,
Apr 26, 2020, 9:29:44 AM4/26/20
to django-d...@googlegroups.com
I understand that this will probably get shouted down due to the
popularity of JWTs, but: I don't think Django should include any type
of JWT support in the core framework.

JWTs are an absolute security nightmare. Some of the Django security
team have heard me rant on this topic already, but: there is no such
thing as a safe JWT implementation, because there are fundamental
flaws in the design of JWT that cannot be remedied by just writing
better implementations. Supporting them in Django, even to the minimal
extent in the current PR, would encourage users of Django to adopt
them, which goes against our historical trend of pushing best
practices when it comes to application security, and would
significantly add to the security team's burden because of the
increased attack surface JWT support would open up.

If Django does end up shipping some type of JWT support, I'd lobby
very strongly for declaring it out of scope for our security process,
and labeling it "use at your own risk".

Ryan Hiebert

unread,
Apr 26, 2020, 11:01:05 AM4/26/20
to django-d...@googlegroups.com
On Sun, Apr 26, 2020 at 8:29 AM James Bennett <ubern...@gmail.com> wrote:
JWTs are an absolute security nightmare. Some of the Django security
team have heard me rant on this topic already, but: there is no such
thing as a safe JWT implementation, because there are fundamental
flaws in the design of JWT that cannot be remedied by just writing
better implementations.

Given this thesis, your conclusion makes sense. I use JWTs in my application, because my domain is particularly suited to it IMO, and while I can't speak for everyone on this list, I'd be interested to hear your complaints about the design of JWTs. For my own thinking, I find that the inclusion of the standardized algorithm field was a design mistake. It can be papered over by a good library implementation, but that so many libraries got it wrong is evidence of a flaw in the protocol design, IMO.

However, I'm not aware of any other standard payload-signing mechanism that has the well-defined capabilities that JWTs have, without that issue. That's fairly likely to be ignorance on my part, and if a more suitable standard were available to me, I'd happily switch my application to using it. Obviously JWTs are indeed popular, and I don't particularly find that the issue I mentioned above to be a total showstopper (although obviously very unfortunate).

Perhaps in email or a blog post or just a list of links, would you be willing to share your complaints? Are there better designs for a similar protocol that overcome your objections?

Ryan

Adam Johnson

unread,
Apr 26, 2020, 11:47:02 AM4/26/20
to django-d...@googlegroups.com
James, I too would like to know your criticisms! I've always understood that they aren't much different to signed cookies, but I haven't looked too deeply at them.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

James Bennett

unread,
Apr 26, 2020, 10:53:39 PM4/26/20
to django-d...@googlegroups.com
On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson <m...@adamj.eu> wrote:
>
> James, I too would like to know your criticisms! I've always understood that they aren't much different to signed cookies, but I haven't looked too deeply at them.

Well, people asked. So.

The short summary is: JWT is over-complex, puts too much power in the
attacker's hands, has too many configuration knobs, and makes poor
cryptographic choices. This is why we see vulnerabilities in JWT
libraries and JWT-using systems again and again and again.

And even if you get every single bit of it right, in the ideal perfect
world with the ideal perfect implementation, the payoff is you've put
in a ton of work to get something that already existed: signed
cookies, for the use case of session identification, or any of several
better token or token-like systems -- everything from PASETO to just
timestamped HMAC'd values -- for the use case of inter-service
communication.

The longer version goes more like this...

JWT is a more complex thing than many people appreciate. In fact, it's
at least *five* things, each specified in its own RFC, plus some more
you have to know about and implement if you want any hope of getting
the actually-sorta-secure version. And right off the bat, that's
worrying: the more different things you have to implement, and the
more places you have to look to find out what and how to implement,
the more opportunities there are to make mistakes.

This complexity comes from the sheer number of different options JWT
tries to support, which in turn is an anti-pattern. JWTs may be
signed, or they may not. They may be encrypted, or they may not. There
are multiple different options for how to sign, how to encrypt, how to
manage and specify keys... in a well-designed system there would be
far fewer options. Ideally, there'd be only one option, and the
solution for a vulnerability being found in it would be to increment
the version of the underlying spec, and change to something
better.

Anyway. In JWT, signature and encryption schemes are effectively
negotiable, which is yet another anti-pattern: you are putting
enormous power in the hands of attackers to negotiate you down to a
bad, or nonexistent, cipher/algorithm for encryption or signing. TLS/SSL
learned this lesson the hard way; JWT has chosen not to learn it at
all. Worse, JWT embeds the negotiation about how to handle the token
into the token itself. This is just asking for trouble, and in fact
trouble has routinely occurred. As a somewhat sarcastic author of my
acquaintance put it:

> It is extraordinarily easy to screw up JWT. JWT is a JSON format
> where you have to parse and interpret a JSON document to figure out
> how to decrypt and authenticate a JSON document. It has revived bugs
> we thought long dead, like “repurposing asymmetric public keys as
> symmetric private keys”.

(from: https://latacora.micro.blog/a-childs-garden/)

More succinctly: JWTs inherently and unavoidably violate the
Cryptographic Doom Principle
(https://moxie.org/blog/the-cryptographic-doom-principle/). Worse,
JWTs put full control of the violation in the hands of the attacker,
who -- thanks to the high level of configurability JWT offers -- is
free to find the set of options most likely to compromise you, and
foist them on you.

That quoted line above about revived long-dead bugs is no joke,
incidentally. Here's one from a few years back:

https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/

Five different libraries, written in three different languages, all
had the same bug. I once had the misfortune of arguing with someone
who attributed this to the libraries being built by bad programmers,
or in bad languages. But I personally tend to agree with a line from
this talk:

https://www.okta.com/video/oktane19-cryptographic-wrong-answers/

> Now you can say look those are all implementation vulnerabilities,
> it's not actually JWTs fault, I disagree. If I can find the same
> vulnerability in five popular libraries, then maybe the spec did a
> bad job of making sure people avoided that vulnerability.

So to completely head off the "it's just bad implementations"
argument, let's turn to the specs themselves: RFCs 7515, 7516, 7517,
7518, and 7519 are the core specifications that make up with is
commonly called "JWT" (and in RFC-land is more properly called "JOSE"
-- "JSON Object Signing and Encryption", of which the token format is
but one part).

The JOSE RFCs make a number of choices regarding default sets of
standardized cryptographic options. For example, RFC 7518 standardizes
thirteen signature algorithm options, seventeen encryption key
management options, and six different encryption cipher options.

This is already a problem -- that's an absolutely gigantic
combinatorial space of options! But then it gets worse.

Let's look just at the first table of options in that RFC, which is
for signing algorithms. It categorizes them as "Required",
"Recommended+", "Recommended", or "Optional". It then places into its
"Recommended" category options like RSASSA-PKCS-v1_5, which was known
to be vulnerable to Bleichenbacher's attack nine years before this RFC
was written (and Bleichenbacher's attack on PKCS#1 in general had been
known for 17 years at that point).

And then if we read a bit further we find ECDSA with P-256 is in the
"Recommended+" category, which the RFC helpfully says means that it is
likely to be bumped up to "Required" in the future. The P-256 curve
is... controversial, to say the least, and it took several additional
years before RFC 8037 finally standardized a better alternative
(Ed25519).

And that's just one quick glance at one table of one set of the
available options in one of the five core RFCs.

Here's another set of critical vulnerabilities:

https://blogs.adobe.com/security/2017/03/critical-vulnerability-uncovered-in-json-encryption.html

Five different libraries, for three different languages (and a
*different* set of libraries and languages than the previous
critical-vulnerability post I linked), all vulnerable to the same
basic invalid-curve attack.

Here's another one from just ten days ago:

https://insomniasec.com/blog/auth0-jwt-validation-bypass

Auth0's JWT validation was tricked into accepting unsigned tokens
thanks to a bug in parsing the (attacker-provided and
attacker-selected!) "alg" header parameter.

I could go on with this, but the general idea I'm trying to get across
is: JWT's issues are not just due to specific implementations being
bad. Several are issues that come with JWT itself, and are baked into
its design and specifications. The existence of vulnerabilities in
popular libraries is thus an expected consequence; no amount of
brilliance on the part of library authors can correct for the inherent
problems with JWT.

Meanwhile, we have access to alternatives that are simpler, more
robust, or often both. Django already supports at least two of them
out-of-the-box. As a result, I remain *strongly* against implementing
support for JWTs in Django, in any form, even the draft subset
implementation Claude has posted.

Ryan Hiebert

unread,
Apr 26, 2020, 11:45:29 PM4/26/20
to django-d...@googlegroups.com
On Sun, Apr 26, 2020 at 9:53 PM James Bennett <ubern...@gmail.com> wrote:
On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson <m...@adamj.eu> wrote:

The short summary is: JWT is over-complex, puts too much power in the
attacker's hands, has too many configuration knobs, and makes poor
cryptographic choices. This is why we see vulnerabilities in JWT
libraries and JWT-using systems again and again and again.

And even if you get every single bit of it right, in the ideal perfect
world with the ideal perfect implementation, the payoff is you've put
in a ton of work to get something that already existed: signed
cookies, for the use case of session identification, or any of several
better token or token-like systems -- everything from PASETO to just
timestamped HMAC'd values -- for the use case of inter-service
communication.

Thank you very much for this write-up. The mention of PASETO was particularly helpful to me. I was aware of the big all-library issue due to algorithm negotiation and public/symmetric forgery, but not the others you mentioned.

For my use-case, I need a signed payload that is server-verified and client-readable. It sounds like PASETO is what you might recommend that I use, instead of JWTs, IIUC.

Would you think that the motivation that started this thread might be well served with having that as PASETO, or would it be better in your estimation to avoid either JWT or PASETO in Django at this time? I can imagine that Django using PASETO could give it a signal boost, but of course if there were discovered some design flaw there, it would also entrench it more as well as making it a security issue that Django has to address.

Either way, I really appreciate you taking the time to let us hear your thoughts.

Ryan

Tom Forbes

unread,
Apr 27, 2020, 3:06:12 AM4/27/20
to django-d...@googlegroups.com
Thank you for the fantastic summary James. You’re spot on about the various implementation issues that plague JWT libraries.

While I think it’s an OK technology if you use a very explicit subset and you know what you’re doing (see https://github.com/google/jws) it is indeed a bit of a minefield and I’m not sure we should be promoting it.

That being said, are signed cookies really a suitable replacement for JWTs? Right off the bat there is a size limit that’s shared with other cookies on your domain, and you might not want to (or be able to) encode the data in a cookie to begin with.

Maybe we can update the docs to show how you you would might use some of the signing primitives instead of JWTs, but this also sounds a bit dangerous 🤷‍♂️ 

On 27 Apr 2020, at 03:53, James Bennett <ubern...@gmail.com> wrote:

--
You received this message because you are subscribed to the Google Groups "Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.

Steven Mapes

unread,
Apr 27, 2020, 5:37:30 AM4/27/20
to Django developers (Contributions to Django itself)
I completely agree with James. I felt dread when I saw a JWT Thread appear as, for me synonymous with flaws security and I'd rather Django stay well clear of them

Adam Johnson

unread,
Apr 27, 2020, 8:21:04 AM4/27/20
to django-d...@googlegroups.com
Thank you very much James. I've learned once again that "everyone is using it" does not make it good.

(Would love if you pasted your write up on your blog to make it easier to share)

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

Derek Adair

unread,
May 11, 2020, 9:37:44 AM5/11/20
to Django developers (Contributions to Django itself)
Maybe we can update the docs to show how you you would might use some of the signing primitives instead of JWTs, but this also sounds a bit dangerous 🤷‍♂️ 

As someone hoodwinked into believing JWT was the way... I'd absolutely LOVE a clear and concise write up on how I might get my single page js apps to communicate securely with projects like Django Rest. 

Thanks for closing the door on JWT for me James.

Dan Davis

unread,
May 11, 2020, 7:19:33 PM5/11/20
to Django developers (Contributions to Django itself)
The place where JWT begins to get useful and important is when federated login capabilities end-up in your app. That sort of thing seems more the domain of python-social-auth packages like social-auth-core and social-auth-app-django.  Generating an authentication cookie doesn't require JWT - Django already does that.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.

Andrew Wang

unread,
Jan 16, 2021, 10:46:35 AM1/16/21
to Django developers (Contributions to Django itself)
Hi all, I know this is an old thread, but I have a solution for SPAs using httpOnly session cookies. Here is a demo with React and Django WITHOUT JWTs with httpOnly cookies for session and csrf: https://acwpython.pythonanywhere.com/authenticated/. The tutorial and open source repository is found here: https://github.com/Andrew-Chen-Wang/SPA-with-httponly-sessions .

The original purpose of this thread was for SPA development, not really for JWTs. I'm a maintainer at SimpleJWT, a repository that almost all tutorials use to show React/SPA/JS Frameworks and Django integration. I also agree with the security concerns for JWT usage on the browser. So I made this demo and tutorial overnight to make sure everyone stops using JWTs instead of sessions.

Thanks for taking a look. Please spread the word to get people to stop using JWTs instead of sessions.
Cheers 

Carlton Gibson

unread,
Jan 19, 2021, 9:55:04 AM1/19/21
to Django developers (Contributions to Django itself)
Hi Andrew, 

Thanks for updating — that's really interesting to look at. I think a few more examples like this around the community would be handy to break the "Must use JWT" presumption that I think there is. 

Kind Regards,

Carlton


Andrew Wang

unread,
Jan 19, 2021, 11:18:06 AM1/19/21
to django-d...@googlegroups.com
Hey Carlton,

Thanks! There's actually already a package (django-webpack-loader) designed to handle exactly what I did, but being a maintainer of SimpleJWT made me realize most Django devs weren't using it. I basically almost completely blame all the tutorials that keep using SimpleJWT to do the task. This article: https://www.valentinog.com/blog/webpack-django/ talks about two reasons (besides people bandwagoning off SimpleJWT tutorials and making their own): webpack maintainability and in general the JS bundles growing too big and thus slowing dev time. I think even if there is wide adoption for webpack, because of the JS bundles continuously growing (being a huge turn-off once you have a semi-production-grade SPA repository), I proposed a moderate idea:

To fix this, I'm going to develop a middleware as described in issue #3 here: https://github.com/Andrew-Chen-Wang/SPA-with-httponly-sessions/issues/3 It'll use JWT when you're delivering on Node and SessionMiddleware when delivering your bundles via staticfiles. That way, a webpack loader is not needed and development time is extremely fast. Deploy your staticfiles on GitHub pages with the provided action; use React hot-reloading during development so you don't need a webpack loader, split chunking, etc..

But thanks for taking a look! I'll update this thread once more when I develop a package or just create that middleware.

Cheers,
Andrew

You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/6oS9R2GwO4k/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5f14dd99-f73c-4415-ac94-95c6560f7d74n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages