71

I've implemented a basic authentication system with Spring Boot, Spring Security, OAUTH2 and JWT as auth tokens. It works alright but I was thinking if it makes sense to store JWT in a database and check if a token exists every time someone makes an authenticated request using it? I was thinking specifically of the following scenario: user is authenticated in a mobile device and they lose it so they want to deauthorize that device. They would then be able to issue an operation that clears the tokens issued to their user id and deauthorize all tokens assigned to him. Any other way? Am I thinking this wrong or overcomplicating things?

This is for securing a REST API that is going to get called from a mobile APP.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
laurentius
  • 1,093
  • 1
  • 9
  • 20
  • 1
    I wanted to answer this question, but already closed. I am learning JWT recently. To me, storing in DB is the only way to verify the token. Otherwise you are just trusting the token that came from a client. When a token comes from client it could be modified by somebody. Only to know it is not modified is by comparing this token with the one we generated in the first place. Also this approach solves the problem of instant Logout and Revoking Access. If you are looking to minimize the DB latency then you can consider implementing a secondary level cache around the DB e.g. Memcache. – tusar Aug 28 '21 at 13:00
  • 8
    @tusar nonsense, JWT cannot be modified. To modify a JWT you would need a private key which (hopefully) only the JWT issuer knows. If you modify the JWT, the verification fails. This is the whole point of the JWT: if you can verify the JWT, you can trust it. – maxgalbu Nov 02 '21 at 10:58

2 Answers2

95

You could store the JWT in the db but you lose some of the benefits of a JWT. The JWT gives you the advantage of not needing to check the token in a db every time since you can just use cryptography to verify that the token is legitimate. If you have to look up the token in the db, you might as well just use an opaque token that doesn't carry information with it and let the server and database provide you with the information. On the other hand, if you're going to store a token in the db, I don't think a JWT is a bad choice for your token type. As you say, there are advantages for revocation if you store your token in the db. It all depends on what you want to achieve (faster authorization, etc. vs ability to revoke on demand).

You can still use JWT with OAuth2 without storing tokens in the db if you want. JWTs have a configurable expiry time that you can set--after which they are invalid. Access Tokens (whether JWT or not) should usually be short-lived for security. If the concern is someone's phone being stolen and access tokens being obtained, I think the solution is to have those tokens expire quickly (30 mins?). If you're using oauth2, the means of stopping someone from continuing to use the app is for the real owner to de-authorize the mobile app client on the authorization server so that no more access tokens will be given out.

sdoxsee
  • 4,451
  • 1
  • 25
  • 60
  • So you think I would be better server sticking with OAUTH2 (project requirement, needed to interface with another API) default tokens, store them in the database and scrape JWT? For this instance I don't really need to store data within the token (I was doing it anyways to access some common and regularly regularly accessed but I can really get by without it). – laurentius Mar 13 '17 at 15:48
  • added a second paragraph to answer your question – sdoxsee Mar 13 '17 at 16:56
  • How do you solve deauthenticating a jwt if it isn't stored in a DB? If a phone gets stolen for eg. and the 30 mins hasn't lapsed the thief has unlimited access to the users data until after the 30 mins elapse. – Byrd Apr 22 '17 at 01:07
  • You can revoke JWTs but it comes at a cost (e.g. http://stackoverflow.com/a/40385939/1098564). Practically, even with reference tokens (database stored tokens), if someone stole your phone, you'd have to whip out, get to, or find another device and determine how revoke the token. I imagine that it would take the average person at least 5 minutes after they discover their device is stolen and find another device to log in, find the latest token and revoke it. You can always shorten the JWT expiration times to an acceptable level of risk. Or you can find mechanisms to revoke it. – sdoxsee Apr 22 '17 at 03:15
  • Yeah seems like revocation comes at a huge cost to not even consider using JWT. You want a self contained authentication, however if you do it that way if someone takes said JWT and it has yet to expire than the account is fully accessible to anyone. My main concerns were two fold. One the theft of JWTs which is a rather small edge case, the other would be if a user changed their password, already issued JWTs would still be active as you don't really have any means to go back to said JWTs and revoke them cause it is self contained and not on your DB. Unless you put it there,losing the benefits – Byrd Apr 22 '17 at 05:04
  • To be fair, deleting db-stored reference tokens upon password change is not part of the oauth2 spec so you can't expect that behaviour unless the specific implementation advertises that. Often you'd have to provide this custom logic yourself (e.g. http://stackoverflow.com/questions/33211791/oauth2-handle-password-change-in-spring-security). – sdoxsee Apr 22 '17 at 11:57
  • 3
    I have a question - I keep seeing JWT used for authentication. But the main advantage is that you can carry data around with it. But to implement a logout on a site, requires you to have a blacklist of sorts to check if the jwt is valid (because there is no way to mark a JWT as invalid in real time only expiry). So then as this post suggests you lose some of the benefits of JWT. So why would you still use JWT at all, instead just use the db for login/logout? Are there any benefits to using JWT once a blacklist is put in place? – tcoulson Jul 26 '18 at 13:38
  • 2
    @tcoulson, to clarify... "Logging out" of an RP doesn't necessarily imply logging out of the authorization server (AS) that issues the tokens nor does it imply that previously-issued access tokens become "blacklisted" (JWT or not). "blacklisting" access tokens is a choice (outside the oauth2 spec) that, IMO, greatly reduces the value of choosing JWT. The only advantage I see to JWTs with blacklisting is that it's easier to inspect token claims via https://jwt.io/ than the DB. JWTs with blacklisting also have disadvantages like token size on every call plus the latency of the DB checks. – sdoxsee Jul 27 '18 at 01:55
  • 1
    what is an RP? Totally agree with the advantages. I got around the one problem of blacklist length of token size by giving the token a jti and saving that unique key instead. But I still have the issue with having the check the server whenever someone enters my app. And I don't see a good solution for using JWT alone for my authorization. I still see a huge use for passing user details around in the JWT, especially things that are just informational. Thanks for your response @sdoxsee – tcoulson Jul 27 '18 at 14:51
  • 2
    sorry for not defining terms @tcoulson. RP = Relying Party (or Client). I was using openid-connect terminology. – sdoxsee Jul 27 '18 at 15:14
  • So how do you check auth in AS vs. RP? – tcoulson Jul 27 '18 at 16:00
30

You can set expiration date (for mobile 1 week). Add some custom field refreshId for user (you can use uuid for this). Next set Issued at claims parameter ("iat"). Store refreshId into db and set it as claims parameter . Then every time when you validate token you should check the token's "age". If it older than one hour you should load data from DB and check refreshId value and create new token with current "iat" value and send it to mobile device. When you need to deactivate tokens just generate new value for refreshId in db. After one hour all tokens will be incorrect, so user will need to login on every device again. You can make more custom solution if you need to.

Jan Pavtel
  • 678
  • 5
  • 8
  • 1
    This seems like a great approach - best of both worlds, still getting the JWT benefit of not needing to check the token against the database, but having the ability to revoke (not instantly, but still the ability). – Donald Jul 10 '18 at 20:43
  • 2
    It wouldn't take long for a rogue user (ex-employee?) to cause havoc. I think the ability to immediately revoke access should not be forgone. – java-addict301 Feb 06 '19 at 20:33
  • 2
    If you have access to the DB to "revoke access" your system is already fully compromised. – jscul Sep 07 '21 at 17:40