How to securely store refresh tokens in mongodb database - mongodb

I'm trying to tweet on behalf of Twitter user using How to connect to endpoints using OAuth 2.0 Authorization Code Flow with PKCE.
A refresh token allows an application to obtain a new access token without prompting the user.
In order to post on behalf of the users when they are offline I assume the app needs to store this refresh token that Twitter gives it in the database to persist.
But is there a best practice for storing these tokens? I'm using mongodb.
I found this:
The recommended approach is not to store access tokens, but get the
access tokens as needed. Securely store only the refresh tokens, with
as much rigor as if they were access tokens.
-src
But the instruction that followed seemed to be specific to Azure.
How would you store a refresh token with rigor? What does that mean for mongodb?

I think this is a bit of an opinionated question. My answer here is more notes than a good answer
But here's the opinions I found so far from different devs and how to handle them.
Encrypting the refresh token is overkill
I think that quote was for a different use case of oauth2. Maybe for using oauth2 also as a login to your app you would have to be more careful with the refresh tokens, though I'm not sure.
But for my use case it seems ok to store the refresh token in the db unencrypted.
A hacker would need to steal the refresh token AND the client secret to get an access token. The client secret is stored in an env file. So the refresh token alone wouldn't allow a hacker to do anything with it.
You should encrypt the refresh token
Yes, a hacker would need to steal the refresh token AND the client secret to get an access token. But if they came that far, they could use the client secret to ask for more rights and take over the users twitter accounts. So there may be some motivation for a hacker to do that- if they realize they could take over thousands of twitter users accounts. I'm not really sure how you would encrypt the keys for mongo, maybe there is something similar to azure vault or maybe you can use vault with mongo.
Rebuttal to #2: If your env is secure, which it should be, you don't have to worry about your client secret getting compromised.
So my take away is this is sort of opinionated

Related

oAuth Silent authentication vs refresh token and http only cookie

Somehow implementing stateless authentication always brings me headaches.
This time it concerns silent auth vs refresh tokens.
Using refresh tokens seems discouraged, however there are certain arguments I don't really get.
If you use an http only cookie to store your refresh token, what exactly is the danger?
Attackers cannot get access the cookie with Javascript and if you use SSL (which you should), I really don't understand the problem.
The resources I read always say "you should not store sensitive data in the client". Seems like an automatic, but that is implicitly impossible if you want to eliminate the need for server session state. Neither do I really understand why, since no resource ever explains how it would be cracked (and I really wonder if anybody really knows).
The reason why I have this question is because using a refresh token offers me more than just authentication.
If a user for example loses his / her device, removing the refresh token will just invalidate all access tokens over all devices (not only browser), which seems like something a user wants to do.
After all, it makes sense that when you lose a device, you need to take action to protect your data.
So the argument "if the attacker gets access to the refresh token, he can infinitely refresh your token" sounds like another argument I don't get. The attacker should not get the refresh token. How would he ever get it? It's the same as saying "if the attacker gets hold of the code of your bank card, he has infinite access to you money". Well if you lose your bank card, you call card stop; likewise if you lose your refresh token, you would delete it to invalidate all access tokens. So how is this an argument?
Can you clarify why I cannot just store my refresh token in an http-only cookie, and how a silent authentication flow improves on this?
Edit:
Note that I read a few other articles that advise to store jwt in the browser by sending the encrypted jwt signature in an http-only cookie. These articles received a lot of upvotes, so that is suddenly okay. It makes zero sense to me.
Edit on comment:
The architecture is very simple:
React / Redux SPA with REST api in the backend
Need for social login through Google, LinkedIn, Github
Need to refresh the token without needed user interaction
Access my own api resources (preferably with jwt)
Ability to revoke refresh token
I don't know why it seems complex (lol).
Refresh tokens are widely used in:
Server side web apps, where they are stored in an HTTP only cookie, as you suggest
Desktop and mobile apps, where they can also be stored in OS secure storage
Refresh tokens should not be infinitely renewable and often represent the user session time - eg:
Refresh token / User session lifetime = 12 hours
Access token / API message credential lifetime = 60 mins
The concern for SPAs in the above article is that there is no real secure storage in the browser - though you are not intending to use browser storage - so no problems there.
One risk is that users can maybe get the secure cookie and replay it to an API via browser developer tools:
To mitigate this it is of course important to ensure that APIs have well engineered authorization - and that what the user can do with a token matches what they can do in the UI.
Another risk is CSRF where a malicious app in another browser tab sends the same cookie to your back end. So you'll need to protect against this.
Note that SPAs have their own token renewal solution based on Authorization Server cookies - I would prefer that option if using an SPA, rather than issuing your own cookie.

Using a JWT for more than authentication

Should JWTs be used for more than just authenticating a user? I read that it's okay to store non sensitive stuff like a user ID in it. Would it be okay to store stuff like permission levels in the token? This way I get to avoid doing a database call.
JWT tokens can be used for authentication purposes, but nothing stops you from creating your own claims to store additional data, such as the user roles or a scope of access.
Some authentication providers add a scope of access to their tokens. Have a look at this answer.

JWT authentication & refresh token implementation

I am developing a REST application with its own authentication and authorization mechanism. I want to use JSON Web Tokens for authentication. Is the following a valid and safe implementation?
A REST API will be developed to accept username and password and do the authentication. The HTTP method to be used is POST so that there is no caching. Also, there will be SSL for security at the time of transit
At the time of authentication, two JWTs will be created - access token and refresh token. Refresh token will have longer validity. Both the tokens will be written in cookies, so that they are sent in every subsequent requests
On every REST API call, the tokens will be retrieved from the HTTP header. If the access token is not expired, check the privileges of the user and allow access accordingly. If the access token is expired but the refresh token is valid, recreate new access token and refresh token with new expiry dates (do all necessary checks to ensure that the user rights to authenticate are not revoked) and sent back through Cookies
Provide a logout REST API that will reset the cookie and hence subsequent API calls will be rejected until login is done.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
A REST API will be developed to accept username and password and do
the authentication. The HTTP method to be used is POST so that there
is no caching. Also, there will be SSL for security at the time of
transit
This is the way most do it, so you're good here.
At the time of authentication, two JWTs will be created - access token
and refresh token. Refresh token will have longer validity. Both the
tokens will be written in cookies so that they are sent in every
subsequent requests
Storing the tokens in cookies I not dangerous in itself, but if you somehow get you JWT module on your server to read them from there you vulnerable to CSRF attacks where any webpage can trigger a users browser to send a form + you sites cookie to your server unless you use CSRF tokens. So generally they are stored in localStorage and "manually" added to request headers every time.
On every REST API call, the tokens will be retrieved from the HTTP
header. If the access token is not expired, check the privileges of
the user and allow access accordingly. If the access token is expired
but the refresh token is valid, recreate new access token and refresh
token with new expiry dates (do all necessary checks to ensure that
the user rights to authenticate are not revoked) and sent back through
Cookies
Apart from the cookie dangers, it seems safe.
Provide a logout REST API that will reset the cookie and hence
subsequent API calls will be rejected until login is done.
You don't even need to make an API call, you can simply just purge the cookies or the localStorage object and make sure your client doesn't break on missing tokens.
The standard for the express-jwt module expects the tokens to be in its own "Authorization: Bearer [Token]" header, which I would strongly recommend over cookies. The localStorage API is available all the way back to IE8 so you should be good.
Edit:
First, it's important to know the difference between XSS and CSRF attacks since they're often believed to be the same thing.
XSS is when users get unsafe JS running on your domain in other users browsers when that happens neither JWT in localStorage or sessions and JWT in cookies are safe. With httpOnly flag on cookies, you can't directly access them, but the browser will still send them with AJAX requests to your server. If this happens you generally out of luck. To prevent this, make sure to escape all user input if it's sent to the browser.
If you load 3rd party JS with script tags or iframes this might compromise localStorage unless you are careful, but I haven't worked enough with this to help you here.
CSRF is only when other domains are trying to send normal HTML forms to your server by getting the browser to send cookies automatically. Frameworks prevent this by inserting unique random strings as hidden fields and checking them again when it's submitted. JWT's in localStorage is safe from this since each domain gets its own separate localStorage area.
But ultimately all this depends on if your service will be using one single domain, in which case httpOnly cookies will be plenty secure and easier to set up, but if you wanna spread your service out on multiple domains like api.domain.com + app.domain.com or add a native app you're forced to store you're JWTs in localStorage or some other native storage area.
Hope this helps!
I asked this question two years back and also accepted the answer. However, based on my experience and study in the last two years, I'd like to answer this just in case someone stumbles on this thread with the same question.
The approach mentioned in the question is similar to the "Resource Owner Password Credentials" grant type of OAuth 2.0. However, I think it is better to use the "Authorization Code Grant" type instead and Cookie to store the tokens instead of browser localStorage or sessionStorage. I have detailed my reasons, implementation points, security considerations and references in this StackOverlow answer.
Like OP I been using resource owner password grant.
I learned so much from Saptarshi Basu's other answer in a different post I think anyone looking into OAuth Code Flow should take a look at it, it has outlined a very solid approach to auth SPA and resource servers. It primarily relies on your backend(resource server) to handle authentication with the auth provider as a private client.
However, I will just add that people looking at implementing authentication with SPA should also consider OAuth Code Flow with PKCE. The main goal of PKCE is to allow public client such as SPA to authenticate directly with auth provider. All PKCE adds, is that when a SPA app initiates authentication, a hashed value is sent to the auth provider when the user is authenticated. And after user authenticate with the authorization provider, it redirects the user back to SPA with that hashed value as well as authorization code. Now, for the next part where the SPA calls auth provider to exchange code for tokens, instead of providing client secret, it has to provide the key that was originally used to create the hashed value. This mechanism guarantees the code cannot be used by someone who intercepted the code, and the SPA doesnt need to store a client secret like a server-side app does.
Now the only thing I'm not certain at this point is which is technically more secure, server-side authentication using standard Code Flow without PKCE or SPA authenticating directly using PKCE? Most resources I could find online currently describes and recommends the latter . However I feel that letting a private server side client handle authentication (as Saptarshi Basu described) might still be more secure. I would love to hear his opinion on this as well.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
Assuming you're talking about using JWT as Bearer-token in OAuth (and I would strongly advice to follow the OAuth 2.0 protocol), that's right.
With an additional auth-time (timestamp of authentication) claim in your JWT, you could even drop the second token and sent your access- as a refresh-token (the auth-server could then issue a new access-token if token is valid & auth-time within allowed range)... but sure, it's also good to follow the standard ;)
Anyway, there are certain additional aspects (that tend to get difficult or are even against the fundamental ideas of JWT) you should consider before using JWTs as refresh-token, as this basically means you introduce long-living JWT:
do you need to have something like forced user logout/ token revocation by subject (e.g. if user got identified as fraudulent)?
do you need to have something like revocation of a specific token (e.g. if a user looses a device)?
...
Dependent on your use-case you should consider all the possible implications, long-living tokens have as they usually require you to introduce some kind of state on your server-side (e.g. to allow revocation/ blacklisting). Keep in mind the beauty and security of the JWT concept lies within JWTs being short-lived.

Is "logout" useless on a REST API?

Considering that, by definition, a REST API is stateless: is the "logout" operation useless?
I mean, I'm creating a REST API using encrypted JWT. Each token has an expiration time of, let's say, 60 minutes. If I save on a database table the last tokens generated by the API, the "logout" would be done deleting them from the table of valid tokens. But, if I do that, I understand that the API will cease to be stateless, right?
So, I understand that I shouldn't do that. The only solution that I'm thinking is make the JWT expiration time shorter, to 5 minutes, don't implement a "logout" operation and just let the tokens expire.
Is this the correct approach?
I mean, I'm creating a REST API using encrypted JWT
The JSON Web Token (JWT) tokens encodes all the data about the grant into the token itself. The most important advantage of this approach is that you do not need a backend store for token storage at all. One disadvantage is that you can't easily revoke an access token, so they normally are granted with short expiry and the revocation is handled at the refresh token. Another disadvantage is that the tokens can get quite large if you are storing a lot of user credential information in them. So if:
If I save on a database table the last tokens generated by the API,
the "logout" would be done deleting them from the table of valid
tokens
Then you would lose the most important advantage of using JWT and also, still have all those disadvantages, which seems unreasonable to me.
So, I understand that I shouldn't do that. The only solution that I'm
thinking is make the JWT expiration time shorter, to 5 minutes, don't
implement a "logout" operation and just let the tokens expire.
Is this the correct approach?
In my opinion, if you're planning to use JWT, YES! it's better to rely on the token expiration. For more details on this approach you can check this question out.
Is “logout” useless on a REST API?
Regardless of the fact that you're using JWT and similar to any other decent questions on computer science, the answer would be It Depends. The most important advantage of Statelessness is that your API would be more scalable. If you choose this path, probably, every request on your API should be authenticated, since you may need to search a backend store for the given token or decode a JWT token. So, in this case you may have some performance cost on a single node but in a big picture, you would still have the scalability. I guess what i'm trying to say is, if you do not need that scalability, you're better off to choose a Stateful approach. Otherwise, pure REST principles is the way to go.
Automatic token expiry is a separate concern from an explicit "log out" mechanism and, as such, they are both perfectly valid actions regardless of whether your API is ReSTful or not.
When a user logs out they are making a conscious decision to invalidate their access token - for example, if they're using a public computer or borrowing someone else's device temporarily.
Automated expiry is used to ensure that the user must revalidate, in some fashion, on a regular basis. This is good for server-side security.
Access tokens are not about sharing session state between client and server - it's entirely possible to implement an access token system without shared state and the token itself doesn't implement session state, it's only used to verify that the user is who they claim to be. As such, access tokens are not really anything to do with the statefulness of the API.
I think it depends on the behavior that you want for your application, and how secure you need it to be. Do you really need to invalidate the token?
For instance, you could just remove your token from your frontend (browser or app). In theory, it is the only place that stores that particular token. If the token is compromised, it will still be valid until it expires, though.
If you really need to invalidate it server side, a common approach would be to create a blacklist with the token, and clear the expired entries from time to time.
But what if you need your application to accept just one token for each user, like in a bank app that you can only be logged in one device at time? For that purpose the blacklist won't do the job, so you will need to store a single token for each user and check if the passed token is the same. At logout, you would just clear that unique entry. Or you may just use sessions.
So, it is not useless, It just depends on your application.
I would argue that your API is already stateful just by the sheer fact that you have a token around. I also wouldn't get too hung up on REST purity, meaning that everything has to be stateless come hell or high water.
Put simply, if your application requires login, then you need a way to logout. You can't implement a short expiry because that's just going to be a really annoying experience to consumers of the API. And you can't just have no logout at all, because thats a potential security flaw.
I have a similar REST API that I support and I implemented a logout endpoint that is a DELETE call. It simply deletes the token information on the server side and clears any type of authentication for the logged in user.
TL;DR
No, a logout is not useless in a REST API. In fact, for APIs that require authentication, it is more or less a necessity.
With a short expiration time on the token I would think for most applications deleting the token from the client on logout would be a good solution. Anything more would rely on the server and no longer be stateless.
The good solution here would be to delete the token from the user.
So typically when you log in, you will get back a token from the server and store it in localStorage or sessionStorage (depending on the user wanting to be logged in after closing the tab) in the browser, and then send the token from there in the headers with any request that you make to your api.
Then if the user logs out, you don't even contact the api (you don't make any requests to your server), you just clear the sessionStorage or localStorage, use the command localStorage.clear() or sessionStorage.clear() , and then if the user will want to send more requests, he'll have to login again in order to get another token.
One drawback to this approach is, that if a virus, for example gets the token from the local or session Storage before the user logs out then, it will still be able to send requests as you, as the token will still be valid.
One solution to that would be to create a token blacklist in the database, and store the token there if the user logs out, until the token expiration time. However, every time the user would request something, the database would have to be consulted to check if his token is blacklisted, lengthening the process, and making your API stateful.
You can generate a new token that it already expired i.e. expiration is 1sec. and pass it to the user. Any upcoming request will be invalid. This is not optimal solution though..

JWT for stateless API, but session control for security

I really want to use JWT for API access, to keep it stateless. But at the same time I need to have strong security recourse to deny tokens that are yet to expire.
For more sensitive user information APIs I can rely on forcing a fresh login, comparing the IP address, etc. But I still want to be able to revoke a users token if needed. I don't mind paying the overhead price.
What I imagined would be to have each user create their own secret key based on their password, and store it in the session. I don't mind trading the overhead for an easier way to deal with stolen tokens. This way a simple password reset should invalidate old tokens.
Acknowledging the trade off, does this method make sense? Are there better ways to go about this?
You should create a "blacklist" on your server. If a token needs to be revoked, place it in the blacklist and set it to expire from the list when the token expires. For every authentication attempt, you will verify that the incoming JWT is not in the blacklist. Redis can make this quite easy.
Alternatively, consider a third-party service such as Stormpath. Disclaimer: I work for Stormpath. We have an Oauth2 api that let's you issue access + refresh tokens (for a password grant flow). We handle revocation for you, so long as you don't mind the overhead of the REST call to verify the state of the token. Please see Using Stormpath for OAuth 2.0 and Access/Refresh Token Management. We have easy support for this in our Express-Stormpath .library
well, i just had the same kind of implementation. add hashed password to token, and when client returns the token, during validation, check if user's password has been changed in db, if user's hashed pass is not the same as the one you put in token, reject the token. In this way, you don't need to keep any info about user and/or token on the server.
I don't like the idea of white/black listing tokens, so I ended up using the users hashed password + another random key as their token's secret key:
+---------------+------------------------------------+-----------+
| email | password | key |
+---------------+------------------------------------+-----------+
| user#mail.com | asfsifj2fij4f4f4f8d9dfhs.8f8fhsd8h | r4nd0Mk3Y |
+---------------+------------------------------------+-----------+
I then keep a cache in memory of users id=>password+key to verify each users token. This way tokens can be discarded when: 1) user resets password; 2) application changes the user key.
This almost defeats the purpose of JWT's, but I need this layer of security for my use case.
JSON Web Token
JSON Web Token (JWT) is defined by the RFC 7519.
It's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64.
The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server.
Tracking your tokens
You won't need to persist JWT tokens if you don't need to track them.
Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To keep the track of JWT tokens, instead of persisting the whole token, you could persist the token identifier (the jti claim) and some metadata (the user you issued the token for, the expiration date, etc) if you need.
Your application can provide some functionality to revoke the tokens, but always consider revoking the tokens when the users change their password.
When persisting tokens, always consider removing the old ones in order to prevent your database from growing indefinitely.
Additional information
When sending sensitive data over the wire, your best friend is HTTPS and it protects your application against the man-in-the-middle attack.
To find some great resources to work with JWT, have a look at http://jwt.io.