
JWT tokens authenticate the client, not the user - mswehli
https://blog.moodio.co.uk/the-most-important-jwt/
======
barrkel
The distinction between client vs user is semantic quibbling - it's not
possible to authenticate the user, only the agents, or clients, which act on
behalf of the user. We can't interact with the user directly. We can only talk
to the user's agent. JWTs just cache the verification of some secret which we
hope the user has supplied.

What the article actually seems to be asserting is that permission checking
should be done via calls to an IAM and not via claims in the JWT (if I'm
understanding it right).

I don't buy this either. Tokens can cache permissions, albeit with the same
staleness issues that JWTs have for authentication. It's not much different
than how a driving license is both evidence of identity and evidence of a
permission.

The claims might be stale, but we have the same problem for revoking JWTs.

~~~
mswehli
Well yes, but sometimes its not the user that authorizes the JWT token holder
to perform the action to begin with, which is why there is the distinction
between authenticating the user and authorizing a service to perform an
action. JWT tokens don't tell you what the user is allow to do, they tell you
what the service/client is allowed to do on behalf of the user. There still
needs to be a seperate check to see if the user themselves are even allowed to
perform a particular action to begin with, to have even allowed something else
to do it on their behalf, and thats what solves some of the stateness issue,
in that, if you have for example an admin, who gets fired, even if they still
have a valid JWT token that says the client is allowed to perform certain
actions on their behalf, there is still a check to see if the user can perform
those actions, so as soon as they are fired or demoted, the backend will
instantly stop performing actions on their behalf regardless of what the JWT
token says they can do.

~~~
barrkel
> _Well yes, but sometimes its not the user that authorizes the JWT token
> holder to perform the action to begin with, which is why there is the
> distinction between authenticating the user and authorizing a service to
> perform an action._

I think you're talking about delegation now.

> _JWT tokens don 't tell you what the user is allow to do, they tell you what
> the service/client is allowed to do on behalf of the user._

This is delegation, not authorization.

> _There still needs to be a seperate check to see if the user themselves are
> even allowed to perform a particular action to begin with, to have even
> allowed something else to do it on their behalf, and thats what solves some
> of the stateness issue, in that,_

Services which are acting on the user's behalf (delegated) can pass the user's
claims through too; can pass the whole JWT through. That services act on the
user's behalf with delegated authority is a red herring, as far as I can see.

You can still cache permissions (e.g. role) in the JWT. You don't need to do a
separate check using the user's identity, as long as you either have
mechanisms to deal with the staleness of the cache, or you're happy that the
cache lifetime isn't long enough for it to be a problem (nothing happens
instantaneously in distributed systems, after all).

> _if you have for example an admin, who gets fired, even if they still have a
> valid JWT token that says the client is allowed to perform certain actions
> on their behalf, there is still a check to see if the user can perform those
> actions, so as soon as they are fired or demoted, the backend will instantly
> stop performing actions on their behalf regardless of what the JWT token
> says they can do._

This is why you have things like the Refresh and Access tokens pattern. In the
absence of revocation blacklists, claims shouldn't be put into long-lived
tokens.

~~~
mswehli
>I think you're talking about delegation now. > Services which are acting on
the user's behalf (delegated) can pass the user's claims through too; can pass
the whole JWT through. That services act on the user's behalf with delegated
authority is a red herring, as far as I can see.

Whether its delegation or authorization, a JWT access token is the result.
Keep in mind this isn't about the mechanism to how the IAM decides whether or
not to issue a JWT token and to whom, but just what that JWT token means to
the endpoint that will consume the token and decide what to do based on it. >
Services which are acting on the user's behalf (delegated) can pass the user's
claims through too; can pass the whole JWT through

Services acting on a users behalf should not be resending the same JWT token,
if they do you've set it up incorrectly. Each service has its own unique
identifier, as part of the audience claim. A service that gets a JWT token
with a different identifier should reject it, even if the JWT token is valid.

------
Fred27
That's a really poor and incorrect blog post. The author has a very poor
understanding of JWT, has described just one small use case, has decided this
is the only one and thinks everyone else has misunderstood them. That's not
the case. (I agree putting user permissions in a JWT is poor design though.)

Strictly speaking JWTs don't have to be used for authentication at all. They
are just signed tokens containing JSON. You could have a shopping list in
there if you wanted to be sure it was definitely your wife telling you to pick
up milk on the way home.

~~~
Fred27
Sticking with security though - a JWT certainly can be used to identify a
user. The author quote a case where an application have obtained a token on
behalf of the user and that's valid too, but it's a less common (in my
experience) scenario.

A user token tells you (the relying party) that the user has been
authenticated to the satisfaction of the issuer (often Google, Microsoft,
Facebook but it can be anyone inclusing your own authority). You can be sure
the token has been issued by the issuer due to the signature. If you trust the
issuer then you can trust the time-limited token.

As far as how the issuer has confirmed the user's identity and whether it
represents a person, service, etc. can vary.

There 's obviously way more to federated authentication that I want to post in
a comment, but there you go. I believe the OP was getting slightly confused
between some OAuth2 implementations and proper security implementations like
OpenId Connect.

~~~
mswehli
> The author quote a case where an application have obtained a token on behalf
> of the user and that's valid too, but it's a less common (in my experience)
> scenario.

quite common in mine, especially when dealing with service oriented
architecture. the public api is given a token, and it should use that token to
authorize itself to use other services, or a cron job that performs actions on
behalf of users.

> A user token tells you (the relying party) that the user has been
> authenticated to the satisfaction of the issuer (often Google, Microsoft,
> Facebook but it can be anyone inclusing your own authority). You can be sure
> the token has been issued by the issuer due to the signature. If you trust
> the issuer then you can trust the time-limited token.

But my point is (and the point of the article) is thats not what the token
tells you. The token tells you (and the reason its called a bearer token) that
whoever holds this token, can perform the list of actions defined within the
scopes array. Which is completely different to saying we are 100% sure the
user is who they say they are. If the token told you the user is who they say
they are, then why do you even need scopes? You could just assume the user is
allowed to do anything they wanted to to their own resources.

~~~
Fred27
That's really not what scopes are for either. There are a few people on this
thread who are trying to politely explain that you haven't quite got what can
be a reasonably tricky subject. You'd be well advised to step back a bit and
read up on OpenID Connect rather than just digging in on your position and
insisting everyone else is wrong.

~~~
mswehli
Ok... Getting a bit rude, so if you prefer we can end the discussion here,
however first lets take a look at 2 links:
[https://oauth.net/2/scope/](https://oauth.net/2/scope/) "Scope is a mechanism
in OAuth 2.0 to limit an application's access to a user's account."

Literally the first sentence in the definition. If you prefer take a look at
the definition on OAuth definition at
[https://auth0.com/docs/scopes/current/oidc-
scopes](https://auth0.com/docs/scopes/current/oidc-scopes). Now which part of
that exactly anything about authenticating the user or goes against what i've
said? You'd be well advised to take your own advice.

~~~
Fred27
> if you prefer we can end the discussion here

Yeah - let's do that. You're now quoting things that directly contradict your
position, so I'm starting to think we're all just being trolled.

------
unscaled
I've never seen any claims by authors behind JWT claiming the purpose of JWT
is limited constrained delegation, and I highly doubt that is the case.

The fact that RFC specifies a subject claim (for the authenticated principal),
but not claim for clients or scopes, shows quite clearly that delegation was
not the immediate goal behind JWT [1].

JWT and JOSE annoy cryptographers and security researchers so much _precisely_
because they're trying to be a generic cryptographic format that's supposed to
solve everything under the sun. The tragedy of JOSE is that instead of trying
to solve a small set of problems well, it is basically failing at solving any
kind of problem in a satisfactory manner.

JWT can be used in the way described above, but it doesn't seem like
particularly a good fit for this purpose. If we can't trust the clients not to
lie about their users and their delegated claims, we need to make calls to
some mutually trusted STS (or a Token Exchange) anyway. But if we already call
an STS, we can just let the STS produce any type of opaque tokens for any type
of server and let the backend verify the tokens (delegated or not) with the
STS.

[1] Yes, these claims appear in the draft for OAuth 2.0 Token Exchange, but
they came a few years later, and that draft is still not standardized.

------
donatj
> there are far more secure and efficient ways of then verifying what the user
> is allowed to do, such as calling the IAM directly from the backend service
> or by implementing a more complex permissions service.

Making another call over the network for auth is by definition vastly less
efficient by several orders vs having been handed the information in the first
place. The bottleneck of a centralized permission service is actually what
pushed us to JWT in the first place.

Using JWTs to authenticate the user allows actual decentralization of your
endpoints. We have services that speak directly to nothing else in the
ecosystem and it’s a major win.

The security argument is valid to a small extent, but I’ll trust a well salted
SHA256 with my life until I’m told otherwise.

~~~
mswehli
Depends on where the permissions logic is stored, but to add information such
as the example of can user a access the data of company x, then the IAM
provider has to make a call back to the service where this information is
stored. Its unlikely you'd want to store logic like that within the IAM
provider, nor is it necessarily possible. But if you are relying on the IAM
provider for user permissions, then you still have the bottleneck of a
centralised permission service, its just now your IAM provider. The only
scenario i can think of where its more efficent, is in role based
authentication.

------
matsemann
> Blog posts, sign-up pages, and other reading material can't be tried out, so
> can't be Show HNs.

From
[https://news.ycombinator.com/showhn.html](https://news.ycombinator.com/showhn.html)
Edit: The title has removed show hn now

> JWT tokens authenticate the client, not the user

I think it's both. It just doesn't _authorize_ the user for anything special.

~~~
mswehli
Ah thanks. I disagree though, with JWT tokens and especially assuming you’re
using the redirect flow, for the server especially, the server doesn’t need to
know if the user was even authenticated as it could be another service calling
it, it only needs to know that whoever is calling it is allowed to act on
behalf of the user and perform certain actions. An example of this would be if
you connect your email to a CRM system, the crm system at that point might
have been authorised by the user to send emails on their behalf, or might have
been authorised by an admin to send users on everyone’s behalf. In the case
where an admin has given permission then the CRM system can send emails on
everyone’s behalf even if the user themselves were never authenticated. I
believe it is the role of the IAM provider to authenticate the user, JWT
tokens authorise callers to perform actions.

------
dragonwriter
This is kind of a mess. The title says it authenticates the client not the
user, but it doesn't actually talk much about authn. What it actually seems to
argue (with some detail, but incomplete to remotely make the case) is that the
JWT should be used only to validate user->client authz, not user authz.

It fails to really do this, as it notes some IAM systems can be used to
transmit user authz information in it, and it provides no substantive _reason_
to reject that use, it just asserts that it's wrong and that there are
(unspecified) better alternatives (which it also fails to explain how they are
better concretely.)

Waving a hand at more efficient and secure is nice, but show me a concrete
security concern or evidence that another way is more efficient given that I'm
already paying the cost to decode and parse the JWT and maybe I'll believe
you.

------
Koffiepoeder
If you start calling other IAM servers to verify the permissions of the user,
aren't you throwing away the usefulness and advantages of the JwT woken being
a form of stateless auth (isn't the use case of jwt exactly to avoid calling
the IAM upon request?) ?

~~~
mswehli
Well no, JWT tokens are there to validate a call can be made. e.g., that
whoever has made the HTTP call to your API server has been allowed to do so by
the user. JWT tokens aren't there to tell you what the user themselves are
allowed to do. What the user is allowed to do is an entirely different thing
and you shouldn't rely on bearer tokens to tell you that.

------
zemnmez
i think this is conflates the common use of jwts vs their possible use cases.
jwts are just standard signed information after all! Open ID Connect, probably
the best extant user authentication protocol leverages JWTs to build the ‘ID
Token’ that actually encapsulates user identity.

Some conflation between authorisation and authentication here too — the
description of JWTs here describes authorisation, not authentication, I think
‘authorizing the client’ vs ‘authorizing the user’ would typically just be
‘authorization’ and ‘authentication’ respectively.

~~~
mswehli
Well the point is, Authenticating the user happens before the JWT token is
issued, and authorizing an action happens after the JWT token is viewed.
Authorizing a user on the backend to perform an action is an entirely
different thing.

For example, a user signs in and gets a JWT token that has the permission
Delete.Everything which in this example is the permission required to delete
all a users resources, the client takes this and passes it to the backed. On
the backend however, the user might not even be allowed to delete everything.
Maybe they're under investigation, or maybe this particular service just
doesn't allow it. But its not the role of the JWT to tell you whether or not
this particular user is allowed to perform that action, all the JWT token
tells you is that this user has allowed the bearer of the JWT token to perform
that action on their behalf. But, doesn't mean the user is allowed to perform
that action to begin with, so the user has given the client permission to
perform an action they themselves aren't allowed to perform.

~~~
zemnmez
> Well the point is, Authenticating the user happens before the JWT token is
> issued

In the case of OIDC, the ID Token _is_ the contract of authentication. So when
I login via Google, both the consumption of my username / password to produce
the ID Token JWT, _and_ the consumption of the ID Token by the third-party are
authentication.

> For example, a user signs in and gets a JWT token that has the permission
> Delete.Everything which in this example is the permission required to delete
> all a users resources, the client takes this and passes it to the backed.

This is again confusing a common use case of JWT with what it actually is. A
JWT is just a signed token. The concept of a 'permission' used here is an
abstraction upon what JWT really defines, which are 'claims' (i.e. signed
information).

> On the backend however, the user might not even be allowed to delete
> everything. Maybe they're under investigation, or maybe this particular
> service just doesn't allow it. But its not the role of the JWT to tell you
> whether or not this particular user is allowed to perform that action, all
> the JWT token tells you is that this user has allowed the bearer of the JWT
> token to perform that action on their behalf.

This is a usage detail for which there are several valid approaches. It's not
uncommon to see a JWT used as an authentication token _be_ the source of
truth, with only invalidation based on unique id (jti).

The concept of the JWT being correlated with a user authorization is an
entirely synthetic one. It's a common use case. Check the original RFC.

> But, doesn't mean the user is allowed to perform that action to begin with,
> so the user has given the client permission to perform an action they
> themselves aren't allowed to perform.

Consider this counterpoint: if the JWT itself is not itself a statement of
authorization, what's the point in signing it at all? We could just be sending
a unique id corresponding to this token (like a circa 200x OAuth token) and
get the same effect. JWT is used for a common pattern, but it's important to
understand why that pattern is chosen.

------
cameronfraser
permissions are regularly included in scopes and you should be driving access
based on permissions, not roles, roles are just a bucket for permissions.

