2

I'm creating an API along with a SPA for a personal project and I'm hesitating between the following solutions to authenticate users (note: over HTTPS):

  1. HTTP Basic Authentication (send username/password wich each request)
  2. Token based authentication (store SHA1-ed user tokens in the database)
  3. JSON Web Token (JWT) authentication

I don't even consider OAuth cause it seems like a real pain plus I don't need to authenticate with other apps, I'm only concerned about authenticating users.

From what I've read, JWT seems to be a growing standard. It basically holds the caller's data so everytime he makes an API request you encrypt(base64(header) + "." + base64(payload)) with your secret and you compare it with the signature provided in the last part of the token itself. It avoids having to perform DB transactions.

The problem is that if I use JWT 1) I have no possibility to manually revoke specific tokens, and most of all 2) if I change a user's permissions, the previously granted JWT will still have the old data with his old permissions which could grant/restrict him continuous access to some data as long as he doesn't get a new token with his new permissions, which is really problematic and I'm surprised I haven't seen anyone mentionning this problem yet. Moreover, 3) JWT claims to allow the server to validate access without having access to DB but I can't imagine any API request that doesn't involve the database somehow, if only to return data the user asked for. So this argument doesn't make any sense to me.

To me, my best option right now is option 2. Website will have restricted and small traffic so storing tokens in the Database seems like a small and worthwhile trade-off and allow me to do anything I want with these tokens, including managing their lifecycle and permissions. It also avoids exposing the users' credentials like in option 1, in case they use the same ones for other online services.

I just want to know if my concerns about JWT are right or if I misunderstood its functioning? Also, even if I've already read a lot about these different options, feel free to link anything that could enlight me and help me make a better choice. Thanks.

Mickäel A.
  • 9,012
  • 5
  • 54
  • 71

1 Answers1

2

You are right and invalidating tokens before expiration time is a common JWT problem. There are several reason to consider: account deleted/blocked/suspended, password changed, permissions changed, user logged out by admin.

With JWT, you can also set a token blacklist to store tokens that were between logout & expiry time, mark expired and check it in every request. You can include only the ID (jti claim of JWT) or use the last login date and the iat claim (issued at)

Other technique to invalidate tokens when user changes their password/permissions is signing the token with a hash of those fields. If the field value changes, any previous tokens automatically fail to verify.

See https://stackoverflow.com/a/37520125/6371459

Finally, be aware that the token is signed with server private key (not encrypted)

sign(base64(header) + "." + base64(payload))
Community
  • 1
  • 1
pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • Signing with a hash of the user profile fields sounds like a good idea and solves problem **2)**. Thanks for your explanations. – Mickäel A. Aug 16 '16 at 10:21
  • Concerning *token blacklist*, I think if you're going to store anything on dabatase then store generated tokens because it gives you more control on them (and you can't blacklist a previously generated token if you don't save it somewhere anyway at generation time). – Mickäel A. Aug 16 '16 at 10:29
  • 1
    If you do not expect too many tokens to revoke, you also could use an in-memory blacklist. You only need to set an entry after updating critical data on user and `currentTime - maxExpiryTime lastModified` (no more non-expired tokens sent). In this case you would not need to store the entire token. Just `sub`, `iat` and maybe `jti` – pedrofb Aug 16 '16 at 10:39