in Essays  在散文中

Should I Use JWTs For Authentication Tokens?
我应该使用 jwts 作为身份验证令牌吗?

No.


Not satisfied? Fine, fine. I’ll write a longer answer.
不满意?很好,很好。我会写一个更长的答案。

Let’s talk about what we’re talking about. JWT stands for JSON Web Tokens, a reasonably well defined standard for authenticated tokens. Specifically they have a header with format information, a payload, and a signature or message authentication code. The core idea is that whoever has the corresponding verification key can verify that the payload is authentic and has not been altered. What they do with that information is up to them.
让我们谈谈我们正在谈论的事情。 jwt 代表 json Web Tokens,这是一个定义合理的经过身份验证的令牌标准。具体来说,它们具有包含格式信息的标头、有效负载以及签名或消息验证代码。其核心思想是,谁拥有相应的验证密钥,就可以验证有效载荷是真实的并且没有被更改。他们如何处理这些信息取决于他们。

The JWT spec (RFC 7519) makes suggestions by providing a few well-known registered claim names: issuer, audience, subject, expiration time, etc. A common usage pattern is that, after verifying the authenticity against whatever trust relationship they have with the issuer, the recipient checks whether they are the intended audience (if any is specified) and the expiration time has not yet passed, and then take the subject as an authenticated identity of the bearer of the token.
jwt 规范 (rfc 7519) 通过提供一些众所周知的注册声明名称来提出建议:发行者、受众、主题、过期时间等。常见的使用模式是,在根据与他们之间的任何信任关系验证真实性后,发行者、接收者检查自己是否是目标受众(如果有指定)且尚未超过过期时间,然后将主体作为令牌持有者的经过验证的身份。

It’s perfectly designed for bearer token authentication! Or is it? Let me be clear: JWT as authentication tokens are constructed for Google/Facebook scale environments, and absolutely no one who is not Google/Facebook needs to put up with the ensuing tradeoffs. If you process less than 10k requests per second, you’re not Google nor are you Facebook.
它是为不记名令牌身份验证而完美设计的!或者是吗?让我明确一点:jwt 作为身份验证令牌是为 Google/Facebook 规模环境构建的,除了 Google/Facebook 之外,绝对没有人需要忍受随之而来的权衡。如果你每秒处理的请求少于 10k,那么你就不是 Google,也不是 Facebook。

The core benefit, proponents will tell you, is that the recipient of a JWT doesn’t need to connect to the user database to verify the token authenticity and render its service. In a large installation, like Google’s, that means that the JWT issuer, the authentication service, can be a dedicated service that is managed and scaled like other services, and is the only service that needs to access the centralized user database. All other services can act on the information stored in the JWT alone, and don’t need to go through the user database, which would represent a choke point.
支持者会告诉你,核心好处是 jwt 的接收者不需要连接到用户数据库来验证令牌的真实性并提供其服务。在像 Google 这样的大型安装中,这意味着 jwt 发行者(身份验证服务)可以是像其他服务一样进行管理和扩展的专用服务,并且是唯一需要访问集中式用户数据库的服务。所有其他服务都可以单独对存储在 jwt 中的信息进行操作,而不需要通过用户数据库,这将成为一个瓶颈。

What about logout/session invalidation? Well, in order for this model to work, the authentication token should have a fairly short lifetime. Maybe 5 minutes, max. The client is also issued a second token, the so-called refresh token, with which it can request a new authentication token from the authentication service. This gives the authentication service a chance to consult the user database to see whether the user or a specific session has been blocked in the meantime.
注销/会话失效怎么办?那么,为了使该模型发挥作用,身份验证令牌的生命周期应该相当短。最多 5 分钟。客户端还会获得第二个令牌,即所谓的刷新令牌,客户端可以使用该令牌向身份验证服务请求新的身份验证令牌。这使身份验证服务有机会查询用户数据库以查看用户或特定会话是否同时被阻止。

Here’s the twist that is rarely, if ever, spelled out: In this setup the refresh token, not the authentication token, is the real session token. The refresh token represents the session with the authentication service (which can be revoked), while the authentication tokens are just derived credentials to be used for a few requests at most. The beauty, from Google’s point of view, is that this delegates keeping the session alive to the client, i.e. not Google’s servers. Oh and by the way, the refresh token can be, and usually is, opaque, since it’s only ever consumed by the same service that creates it. That reduces a lot of complexity, by just using an opaque identifier stored in a database.
这是一个很少(如果有的话)阐明的扭曲:在此设置中,刷新令牌(而不是身份验证令牌)是真正的会话令牌。刷新令牌代表与身份验证服务的会话(可以撤销),而身份验证令牌只是派生凭据,最多用于少数请求。从 Google 的角度来看,其美妙之处在于,这代表将会话保持在客户端(即而不是 Google 的服务器)上。哦,顺便说一句,刷新令牌可以并且通常是不透明的,因为它仅由创建它的同一服务使用。只需使用数据库中存储的不透明标识符,就可以大大降低复杂性。

Now, let’s assume you are not Google. Check which of these apply to you:
现在,假设您不是 Google。检查以下哪一项适用于您:

  • You wanted to implement log-out, so now you’re keeping an allowlist of valid JWTs, or a denylist of revoked JWTs. To check this you hit the database on each request.
    您想要实现注销,因此现在您要保留有效 JWT 的允许列表或已撤销 JWT 的拒绝列表。要检查这一点,您需要针对每个请求访问数据库。
  • You need to be able to block users entirely, so you check a “user active” flag in the database. You hit the database on each request.
    您需要能够完全阻止用户,因此您检查数据库中的“用户活动”标志。您对每个请求都访问数据库。
  • You need additional relationships between the user object and other objects in the database. You hit the database on each request.
    您需要用户对象和数据库中其他对象之间的其他关系。您对每个请求都访问数据库。
  • Your service does anything at all with data in the database. You hit the database on each request.
    您的服务可以对数据库中的数据执行任何操作。您对每个请求都访问数据库。

Congratulations, if you confirmed any of the items above, you don’t need JWTs. You’re hitting the database anyway, and I’m pretty sure that you only have one database which stores both your user profiles and your application data. By just using a “normal” opaque session token and storing it in the database, the same way Google does with the refresh token, and dropping all JWT authentication token nonsense, you stand to reap these great benefits:
恭喜,如果您确认了上述任何一项,则不需要 JWT。无论如何,您都会访问数据库,而且我很确定您只有一个数据库来存储您的用户配置文件和应用程序数据。通过仅使用“普通”不透明会话令牌并将其存储在数据库中,就像 Google 使用刷新令牌一样,并放弃所有 jwt 身份验证令牌废话,您将获得以下巨大好处:

  • No weird workarounds (allow/denylist) for shortcomings of JWT as authentication token
    对于 jwt 作为身份验证令牌的缺点,没有奇怪的解决方法(允许/拒绝列表)
  • Greatly reduced complexity. No need to manage a secure JWT signing/authentication key
    大大降低了复杂性。无需管理安全的 jwt 签名/身份验证密钥
  • You get to pass on some interesting bugs.
    你可以传递一些有趣的错误。

Just use the normal session mechanism that comes with your web framework and that you were using before someone told you that Google uses JWT. It has stood the test of time and is probably fine.
只需使用您的 Web 框架附带的正常会话机制,并且在有人告诉您 Google 使用 jwt 之前您就使用过该机制。它经受住了时间的考验,可能还不错。

If you need something to do to make you feel like you’re running a big deployment, you can probably configure your session mechanism to use redisvalkey to store the session data. You’re still going to use the authenticated user id to query the database, but for unauthenticated requests it may be faster/use less resources. It might not be. You’ll have to tune and measure that.
如果您需要做一些事情来让您感觉自己正在运行大型部署,您可以将会话机制配置为使用 redisvalkey 来存储会话数据。您仍将使用经过身份验证的用户 ID 来查询数据库,但对于未经身份验证的请求,它可能会更快/使用更少的资源。可能不是。你必须调整和测量它。

This site uses Akismet to reduce spam. Learn how your comment data is processed.
该网站使用 Akismet 来减少垃圾邮件。了解您的评论数据是如何处理的。

14 Comments  14 条评论

  1. I’m not disagreeing with what you wrote for using JWTs as a session token, but there are other use cases.
    我并不反对您所写的使用 JWT 作为会话令牌的内容,但还有其他用例。

    For example, if you have two applications where each has it’s own user and session management, but occasionally you want to send users from one to the other without them having to log in again. One (elegant, imho) solution is that application 1 issues a short lived token and redirects the user agent to application 2, which accepts it as proof that the user has been authenticated.
    例如,如果您有两个应用程序,每个应用程序都有自己的用户和会话管理,但有时您希望将用户从一个应用程序发送到另一个应用程序,而无需他们再次登录。一种(优雅的,恕我直言)解决方案是应用程序 1 发出一个短期令牌并将用户代理重定向到应用程序 2,应用程序 2 接受它作为用户已通过身份验证的证据。

    • You’re right. What you’re describing is formalized in OpenID Connect (OIDC) and the JWT for passing user information from an Identity Provider to a Service Provider is then called the ID token, a third token type (besides access and refresh) in the underlying OAUTH2 protocol.
      你说得对。您所描述的内容已在 OpenID Connect (oidc) 中正式化,然后用于将用户信息从身份提供者传递到服务提供者的 jwt 称为 id 令牌,这是底层 oauth2 协议中的第三种令牌类型(除了访问和刷新之外) 。

      The oauth website has a couple of, erm, Opinions on the topic of whether you’re supposed/allowed to interpret the access token or derive user information from it: https://oauth.net/2/access-tokens/ 😉
      oauth 网站有一些关于您是否应该/允许解释访问令牌或从中获取用户信息的主题的意见:https://oauth.net/2/access-tokens/ 😉

  2. As far as I see it you are mixing authentication, session management and user management.
    据我所知,您正在混合身份验证、会话管理和用户管理。

    For authentication purposes access/refresh token are quite nice since they are rather hard to forge.
    出于身份验证目的,访问/刷新令牌非常好,因为它们很难伪造。

    For user management, well, you do not want to stuff all the required user claims into that poor token. If you try you will find that there is a limit that nobody specified but is there nonetheless.
    对于用户管理,您不想将所有必需的用户声明填充到那个糟糕的令牌中。如果你尝试一下,你会发现存在一个没有人指定的限制,但仍然存在。

    For session management I agree with you. Token are no good session persistence measures, but they do work.
    对于会话管理,我同意你的观点。令牌不是好的会话持久性措施,但它们确实有效。

    Anyway, there is a reason why developers offload that pesky auth/user/session stuff to an identity provider, then all those questions above are “someone else’s problem” (see Douglas Adam for further instructions).
    不管怎样,开发人员将那些烦人的身份验证/用户/会话内容转移给身份提供商是有原因的,那么上面的所有这些问题都是“别人的问题”(请参阅​​ Douglas Adam 以获取进一步的说明)。

  3. I feel like this subject comes up every couple of months with another iteration of why people think JWTs are bad. Claiming JWTs are bad is like claiming that HTTP is bad, data packets are bad, or that currency is bad.

    For sure some RFCs are bad, this is always true, there are things that are always improving. And it’s hard to not point out, that we’ve even built the successful Auth SaaS–Authress–which does provide JWTs, although we thought long about how session management work work.

  4. I am not one for commenting on other people’s articles, but this one just does not make sense to me, and this is why I’ll leave my two cents here: 

    In your headline, you say that you *should* not use JWTs — at the end of the article, you say you do not *need* JWTs. Which one is it? 

    I think that no one ever argued that you absolutely *need* a JWT. The one and only real benefit of a JWT is standardization, and that is exactly why you really *should* use it. 

    Every token format that you implement on your own is — for a developer that is not yourself — always going to be inferior to the JWT if you do not document and specify it as well as the RFC does (Which is something most developers will not do). You *should* always strive to use standards the broader community agreed to, instead of reinventing the wheel because you think you know better than others. 

    Nowhere does the RFC for the JWT mention any type of “refresh token” or “session key” and I think you are wildly confusing JWT and OAuth 2.0 in this article and seem to think that these two things are interchangeable. 

    The JWT RFC only specifies the format of the Token itself, and even the RFC for OAuth 2.0 does not *mandate* the use of the JWT format either. 

    Which flow you eventually use a JWT token in is up to you. This is also why the JWT in and of itself will never have anything to do with the amount of database queries you will make, as these will always part of the authentication and authorization protocols and flows. 

    If you rewrote this article to “You most likely do not need OAuth 2.0 in your application” (the emphasis is on *need* instead of *should* because, again, you absolutely should always strive to use standards), then I would probably agree with you, though.

    • Most applications are designed to work around sessions. Authentication is done once per session and not on every requests. Doing OAuth2 once per session is sensible and after that, you can normally just ignore the JWT token or otherwise store it in the session table for on-demand use. This workflow is well established and common in pretty much all web application frameworks.

      Using the JWT token directly as session identifer would be possible to deal with interfaces that can’t use e.g. cookies, but then you have to canonicalize the JSON to use it as identifier or do the more expensive verification dance. It’s almost always worse.

  5. The article is more about Basic Auth vs. JWT, as I read it.
    And I don’t fully get the problem of using one over the other, or what to recommend in a non Google environment, I have to say. One argument always goes, that you’re trying to avoid sending your password over the wire all the time with Basic Auth. With JWT this is gonna be less. But is that really important? I couldn’t say. I don’t know attack vectors that are working with Basic Auth, but not with JWT.

  6. but JWT is not only that. Token claims can be used to integrate your app with other already written systems. It is client side session not just random number.

  7. I like your thinking. Having been working with the oauth2/oidc/authentications projects with different SaaS products for the last 5+ years have made me question why the default solutions are often times quite complex.

    My favourite example, and the one you already mentioned, is the logout in the SSO scenario. There are still no standard solution to get the logout working if you rely on JWT tokens that are validated on the Relying Party side. Sure there are ways to get it working in some degree, but there are always some gotchas that you need to be aware of. Like the one where you need to balance the token expiration time to make it valid long enough that you don’t worsen the UX of the application, but to make it expire as soon as possible.

    This is a problem that most of these OpenID Authentication services are not telling you. They always sell the idea, that by using their service, you don’t have to implement these things by yourself. But the reality is, that a lot of work is put in the shoulders of the Relaying Parties. Like this logout case. If you would want to to immediately log the user out when the SSO session is killed, you basically have two options: either some sort of event hook in the RP side to get notified when this happens, or regularly check the validity of the token by calling the Identity Provider. Having a webhook for that can be complicated, and the latter just makes you to question why even bother with validating the tokens only in the RP side.

    Sorry, I kind of side-stepped from you original point, but I feel like these paid services companies are using are many times making the problem (you wrote about) worse by not providing things that just work without added complexity.

  8. You’re missing one of the biggest benefits of using JWT’s, interoperability. JWT’s are a known standard, and harder to screw up versus a home baked authN solution.

    Secondly, very few companies should be creating home-baked auth solutions anyways. Unless that’s your core product, there’s no reason to build that kind of risk into your product when things like Auth0/Clerk/Ory exist.

    • I like this one:
      > JWT’s are a known standard, and harder to screw up 

      And then I read even from bigger companies stuff like “alg: none” was accepted…

  9. You’re missing the point.
    There is dedicated software, so-called IDPs that manage users, some also do access management, with an UI.
    The while Oauth2 or nowadays Openid-Connect thing uses JWT, so you can have a token to access multiple backends in a microservice environment.
    In this case the user management (IDP) is a microservice, and your graphql or RESTful backend is a microservice.
    The full stack SSR classic website is a confidential client in this case.
    Yes, oidc means added complexity. You have to deal with X‑FRAME-OPTIONS and CSP, and CORS.
    Advantage is a more secure solution that is more flexible.
    What if you have a service at blog.ploetzli.ch and forum.ploetzli.ch, with oidc you can use a single IDP, aka a single JWT for both.
    Each cookie is only valid in its (sub)domain and path.
    No one is saying you have to use JWT as cookie values.
    You don’t.
    What is your solution when you have a RESTful backend and a mobile frontend, a Svelte SSR frontend and a React PWA frontend and a Qt or other desktop app?
    Do you send each of them a cookie? That won’t work.

    What do you send instead of a JWT? A JWT is a cryptographically signed JSON payload which has a header, body and signature.
    Weakness: The usual suspects are only capable of RSA-SHA256 signing and verification, but that’s not future proof, actually not even now proof. But RS256 is the default for the most prominent IDPs, like keycloak or authentik and some proxies. Louketo for instance can’t handle HMAC-SHA512. Various middlewares also are incapable of doing more than RS256.

    How do you pass information to the client when you have decoupled frontend and backend?
    What is your alternative? Redis? Is the transport encrypted? The documentation says that there is no brute force protection. Also it’s an in memory database.

    OIDC and JWT are standards, that wouldn’t be used if they weren’t working.

    OIDC on the client (or frontend if you will) is more complicated than simple user/password, which btw is also possible with oidc’s password flow.

    If feel like OIDC isn’t the is all end all, there will be another protocol that will succeed it.
    When it works, it’s great, but when it doesn’t you’re in a world of pain.

    Also @fefe, wenn man keine Ahnung hat, Fresse halten.

  10. Lots of inaccuracies in this post. JWTs are great and should always be the preferred option when implementing user authentication and authorization. It is a proven technology with lots of ready-made libraries. 

    Sure, it was designed for scale, but it is also designed for ease of use, which is even more important when it comes to implementing security. It also, out of the box, supports multiple logged in clients for the same user. No need to keep a separate table of session tokes and have a 1‑M relationship from the user table. 

    If you want more security in your app you can exclude the refresh token, that is an optional part of JWTs (it’s not even mentioned in the RFC). Allow/Denylists is also optional (and not really needed unless you have a problem with tokens leaking from your clients, which would mean any token would be vulnerable).

    This article read to me like the author isn’t comfortable using JWTs. I would suggest going through more tutorials on the subject.

Webmentions

  • Stay ahead in web development: latest news, tools, and 2024-05-29

    […] Should I Use jwts For Authentication Tokens?: Short answer: No – but there’s also a long answer 😉 / auth / 16 min read […]

  • New best story on Hacker News: Should I use JWTs for authentication tokens? – Cassinni 2024-05-29

    […] Should I use JWTs for authentication tokens? 405 by pantalaimon | 293 comments on Hacker News. […]

  • Should I use JWTs for authentication tokens? – Latest-News-Events 2024-05-29

    […] Should I use JWTs for authentication tokens? 398 by pantalaimon | 292 comments . […]

  • Should I Use JWTs For Authentication Tokens? – Tinker, Tamper, Alter, Fry | Scriptease 2024-05-29

    […] Should I Use JWTs For Authentication Tokens? – Tinker, Tamper, Alter, Fry — Weiterlesen blog.ploetzli.ch/2024/should-i-use-jwt-for-authentication/ […]

  • Should I use JWTs for authentication tokens? - CIBERSEGURANÇA 2024-05-29

    […] Read More […]

  • Should I Use jwts For Authentication Tokens? pantalaimon on May 27, 2024 at 10:31 Hacker News: Front Page - Bharat Courses 2024-05-29

    […] Article URL: https://blog.ploetzli.ch/2024/should-i-use-jwt-for-authentication/ […]

  • 我应该使用JWTs作为身份验证令牌吗? - 偏执的码农 2024-05-29

    […] 详情参考 […]