Is setting Roles in JWT a best practice?

55,583

Solution 1

Nothing stops you from creating claims to store extra information in your token if they can be useful for your client.

However I would rely on JWT only for authentication (who the caller is). If you need to perform authorization (what the caller can do), look up the caller roles/permissions from your persistent storage to get the most updated value.

For short-lived tokens (for example, when propagating authentication and authorization in a microservices cluster), I find it useful to have the roles in the token.

Solution 2

The official JWT site explicitly mentions "authorization" (in contrast to "authentication") as a usecase for JWTs:

When should you use JSON Web Tokens? Authorization: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.

That being said, from a security-perspective you should think twice whether you really want to include roles or permissions in the token.

(The text below can be understood as a more "in-depth" follow up to the rather short-kept accepted answer)

Once you created and signed the token you grant the permission until the token expires. But what if you granted admin permissions by accident? Until the token expires, somebody is now operating on your site with permissions that were assigned by mistake.

Some people might argue that the token is short-lived, but this is not a strong argument given the amount of harm a person can do in short time. Some other people advocate to maintain a separate blacklist database table for tokens, which solves the problem of invalidating tokens, but adds some kind of session-state tracking to the backend, because you now need to keep track of all current sessions that are out there – so you would then have to make a db-call to the blacklist every time a request arrives to make sure it is not blacklisted yet. One may argue that this defeats the purpose of "putting the roles into the JWT to avoid an extra db-call" in the first place, since you just traded the extra "roles db-call" for an extra "blacklist db-call".

So instead of adding authorization claims to the token, you could keep information about user roles and permissions in your auth-server's db over which you have full control at any time (e.g. to revoke a certain permission for a user). If a request arrives, you fetch the current roles from the auth-server (or wherever you store your permissions).

By the way, if you have a look at the list of public claims registered by the IANA, you will see that these claims evolve around authentication and are not dealing with what the user is allowed to do (authorization).

So in summary you can...

  • add roles to your JWT if (a) convenience is important to you and (b) you want to avoid extra database calls to fetch permissions and (c) do not care about small time windows in which a person has rights assigned he shouldn't have and (d) you do not care about the (slight) increase in the JWT's payload size resulting from adding the permissions.

  • add roles to your JWT and use a blacklist if (a) you want to prevent any time windows in which a person has rights assigned he shouldn't have and (b) accept that this comes at the cost of making a request to a blacklist for every incoming request and (c) you do not care about the (slight) increase in the JWT's payload size resulting from adding the permissions.

  • not add roles to your JWT and fetch them on demand if (a) you want to prevent any time windows in which a person has rights assigned he shouldn't have or (b) avoid the overhead of a blacklist or (c) avoid increasing the size of your JWT payload to increase slightly and (d) if you accept that this comes at the cost of sometimes/always querying the roles on incoming requests.

Solution 3

As mentioned here, ASP.NET Core will automatically detect any roles mentioned in the JWT:

{
  "iss": "http://www.jerriepelser.com",
  "aud": "blog-readers",
  "sub": "123456",
  "exp": 1499863217,
  "roles": ["Admin", "SuperUser"]
}

and 'map' them to ASP.NET Roles which are commonly used to secure certain parts of your application.

[Authorize(Roles = "Admin")]
public class SettingsController : Controller

The server which is giving out (and signing) the JWT is commonly called an authorization server and not just an authentication server, so it makes sense to include role information (or scope) in the JWT, even though they're not registered claims.

Share:
55,583
ayorosmage
Author by

ayorosmage

23 years old developer on smartphone (iPhone and Android). Co-founder of WakeApps (http://www.wakeapps.com )

Updated on July 05, 2022

Comments

  • ayorosmage
    ayorosmage almost 2 years

    I am considering to use JWT. In the jwt.io example I am seeing the following information in the payload data:

    "admin": true
    

    Admin can be considered as a Role, hence my question. Is setting the role in the token payload a habitual/good practice? Given that roles can be dynamically modified, I'm quite interrogative.

  • pm100
    pm100 over 6 years
    the down side of this is that the app has to know this info. In many environments the app has no other access to information about the user apart from claims in the token . So it depends on the exact use case. But yes, it is perfectly normal to add role info to a JWT
  • aruno
    aruno almost 5 years
    Of course you still have to put them in there somehow ;-) This question seems to be a popular way of doing just that - stackoverflow.com/a/42037615/16940 - especially if you're in .NET land and need to create a token with ASPNET roles or role claims.
  • Ziad Akiki
    Ziad Akiki over 4 years
    Thought the 2 words authentication and authorization are the same and used interchangeably. Thanks for the info :)
  • Nate T
    Nate T about 4 years
    Authentication is basically the practice of making sure that the user is who they say they are, and authorization is the process of making sure that the user has permission to access a destination.
  • Nate T
    Nate T about 4 years
    If you are to mistakenly grant an admin permission to a user, and if he or she is willing and able to do significant damage in a really short period of time, then you are likely going to pay a very steep price for your mistake regardless of your authorization implementation. No web security protocol can guard against a threat of that nature.
  • Nate T
    Nate T about 4 years
    Not to mention that the token is passed as the value of the "authorization" key in the header.
  • Kind Contributor
    Kind Contributor over 3 years
    Modern standards like OIDC and central identity systems make use of JWT claims, for full central control over access. Then systems only need to be mapped to the claim. The token from an OIDC can also be used to generate an application specific one.
  • skechav
    skechav over 3 years
    @NathanToulbert Agree 100% . User mistakes and bad practises (while using an app ) are the most weak part of every application..
  • Kaihua
    Kaihua over 3 years
    Want to add a comment about the 2nd approach. Implement a bloom filter to create a blacklist could save a lot of calls to db, so this might improve the cost making a request for every incoming request.
  • Husk Rekoms
    Husk Rekoms over 2 years
    @NateT this is a completely valid comment but it also relates to the talent on your team. There certainly are benefits of using role based tokens when you take performance into account. But I also would not let my JR developers loose on a task that important.
  • Lionet Chen
    Lionet Chen about 2 years
    The exmaple given could be improved. What if a user is granted a token, then before the token expires the user is fired from the job? This might be a more legit reason for prematurely revoking tokens other than huamn error.