Will generating a new client secret invalidate existing refresh tokens? - authentication

As per https://developers.google.com/workspace/guides/manage-credentials#reset_client_secret
after reseting the client secret for a particular client id, will the existing refresh tokens still work or the user must reauthorise?
Have tested the same across google products and can see that existing refresh tokens are still valid. Found couple of discussions denoting the same:
https://groups.google.com/g/adwords-api/c/FbfEA0gC8VU
Generating a new client secret
But couldn't find any official document from google stating the same.

There is no reason why refresh tokens should be invalidated after a client secret reset. I don't remember in what form Google issues refresh tokens, but if they're JWTs then it would actually be quite tricky to invalidate them.
If your tests show that these tokens are not invalidated, then I think that you can safely assume, that, for now, this does not happen on a secret reset.

Related

How to correctly store JWT Refresh Tokens in a database?

I have been using Flask and JWT to create authentication on my backend. Creating and using access tokens is simple enough, but I've run into some conceptual misunderstanding when trying to discover how to handle the usage and storage of refresh tokens.
Upon initial login, I distribute an access token (with 10 minute expiry) and a refresh token (with 4 day expiry). The 'jti' attribute of the refresh token is stored in a table on the database, along with its expiry date. The access token is stored in memory, and the refresh token is stored in HttpOnly cookies. When the access token expires, a "silent refresh" is sent to the backend with the refresh token. It is first checked for validity (user ID matches up, signed correctly, and is not expired), and then the database is checked to see if it contains that specific refresh token's 'jti'. If it does, then that refresh token is deleted from the database (and can therefore no longer be used) and a new access token and refresh token are sent to the user. This allows for the refresh tokens to only be single use. However, if a user logs out and logs back in repetitively, the refresh token cookie in their browser keeps getting overwritten with a new value (which is fine), but the database now contains a ton of references to "unused" refresh tokens. I'm not sure if my understanding of the JWT workflow is completely incorrect, or if this is normal.
I mainly conceptually followed this guide. Is this repetitive logging in and getting refresh tokens normal? I don't see how to manually find and remove older (but still valid) tokens that are used in the same browser.
Your implementation looks fine. It's normal that you issue new tokens for a new session. I think there are two solutions to your problem:
Add a expiration column to your table with refresh tokens. Then you will be able to remove stale jtis from the table once they're expired.
Instead of keeping information about issued refresh tokens, you can keep information about used refreshed tokens. So, when you issue the token you don't save it in the DB. When the user uses the RT, you can save the jti and expiration in the DB. Whenever a RT is used you check whether the jti is in the DB. If it is, you decline the request. You can remove entries from this table after expiration, as you verify expiration on the RT anyway.
I was worried, as you are, when implementing an Access/Refresh flow with overwritting refresh tokens (there are other strategies,as keeping a blacklist and a whitelist).
I discovered that there were two ways to end with "unused" refresh tokens (as you say) or, as I prefer to name them, "stalled" refresh token (you will see why in a second):
First way: LogOut
As you detected Log Out can lead to stalled refreshed tokens in the database.
Probably, you, as me, (and 90% reading this answer) were just "logging out" from the Client side, aka "deleting Access and Refresh tokens" from the client memory/cookies/localstorage and done. Right? Why so?
However, you can send a "/logout" request to your server with your access token (to authenticate) and your refresh token (in the body), so you can delete the refresh token from the database. I would not pass the JTI, but the whole refresh token (after all it is going to be erased shortly afterwards, so no issues if anyone intercepts it with a MIM attack). This way you can double check the user requesting the /logout is exactly the owner of the refresh token (as a security measure), this security check would be lost if you send just the JTI value (which could lead to an attack: an user requesting a refresh token to be erased, through its JTI, from other user). (Yes you can use the JTI to perform a database check to know its owner, but each time the server performs a database call "God kills a kitten", while you can easily compare the user_id in the access against the user_id in refresh token)
Performing a /logout call, each time the user "/logout" you are really killing her refresh token from the database. And hence the ability to create access tokens if the refresh token got compromised (or sniffed) before the user performed a /logout. If an attacker got the "unused" refresh token, even if the user logged out, could exchange it for a refresh and access token again. Let's reduce the "number of refresh tokens" able to create access tokens for an user.
Second Way: Expired Tokens
A second way to have a "stalled" token is when the client tries to /refresh but the refresh token is already expired. In such case, dont just return an error code that will be used by your app to send the user to the Log In page, but also delete the refresh token from the database. Why do you need to keep it? This cleanup strategy reduces the size of your table and helps to clean your database of already expired refresh tokens. You, ofc, will need a script to clean refresh tokens from users "never-returning" to your app or from users who decided to delete localstorage/cookies, but ey! your cleanup script will be fast as hell now.
This second way is the reason I prefer to call all of them "stalled" because they are sitting there (ones being "unused", others being "expired") and filling your table.
Hope these strategies help your security concerns, a pleasure to meet someone as "geek" as me regarding JWT security.

Why do we need refresh tokens in JWT

I'm just learning JWT in nodejs, and I found out about refresh tokens.
As far as I understand, a user gets an access token and a refresh token. After the access token expires, a request containing the refresh token is made to get a new access token. To get a new access token, the server checks if the received refresh token is contained in a database. If the refresh token is stolen, it can easily be deleted from the DB and prevent further refreshes.
My question is: Why don't we just make the access tokens behave like refresh tokens? i.e. We store them in a database and check if they are there when making a request, and when compromised we just delete them?
The key element to answering your question is: You need to add an expiration date on access tokens you deliver to clients. This is the main purpose with refresh token.
Imagine someone steels your access_token, and you didn't make it expirable: It means that as long as you didn't discover that your access_token has been stolen, you're giving literaly a lifetime free pass to whoever has it.
With refresh tokens and expirable access_tokens, you know that the window of vulnerability is really small.
Now your second question: Why don't we make access_tokens behave like refresh_tokens ?
The key idea here is to keep your refresh_token in a safe spot, and only expose access_tokens.
And by the way, refresh_tokens have one job: Carry information to generate new access_tokens, access_tokens on the other hand have their own job: Carry information necessary to give you direct access to resources.
If you pay attention to most serious websites, they have a centralized auth server that serves access_tokens.
Answering comments:
Key difference between them is: refresh token key is like a master key, it stays on the authorization server and is never ever shared with any other server, unlike access token key, it can be passed to another server to authenticate users
in other words:
auth.yourapp.com: stores access_token_key and refresh_token_key
api.yourapp.com: stores access_token_key ONLY, to make sure that users did actualy authenticate on your auth.yourapp.com domain, and api.yourapp.com can easily confirm that. if access_token_key has been compromised, vulnerability has a shorter lifetime, and you can easily isolate the attacked server.
if one of your servers is compromised, the rest is safer.

JWT - per user signing key

In my project there's a requirement to invalidate all jwt tokens of a user when the user changes his password. I was thinking of giving each user a different signing key, and simply reset the key when password is changed. Then I googled around and found Redis is a good place to store those per-user keys. Everything seems to work just fine.
But there one thing I cannot get my head around. Since it has to hit Redis once per request, is it any different than issuing the user an opaque token instead of JWT, and store the token -> JWT payload mapping in Redis?Isn't that defeats the purpose of using JWT?
To invalidate tokens you need to revoke them. OAuth spec also does not require getting secret key from remote server every time you need to validate JWT (as you said it kind of defeats the purpose). The key can be stored locally at resource site.
You have two options here:
1) Introspect the JWT token from resource side against OAuth server every time it validates it. Seems like overkill to me. The best approach is to give short expiration time to JWT token and let the already issued tokens to just expire.
2) Have the resource store the secret key locally and when it fails to validate go and get the key and re-validate it again.
From the point of view of invalidating the token, there's no particular need to store the JWT in Redis - anything that you can check and later invalidate should do the trick.
That said, presumably you're using a JWT for other reasons. For example, it's what the AuthN/Identity service provides. Or perhaps you use it to store claims or other metadata that you validate as part of the AuthN/AuthZ logic. In that case, since it's handy, storing the JWT seems very reasonable.

Generating an API Secret

I have created an API that I only want certain clients having access to. After a bit of research, I found that API Keys and API Secrets are pretty good way of controlling that.
I want to basically generate my own secrets using information I control. For example, if I create the secret 1500315177265-8005550000-System, the secret itself has information I can reference and validate. From what I understand, it doesn't matter what the secret is, as long as its not shared, and that's what makes it a secret. I can append some long salt values to make it much harder to guess. Can I use secrets securely this way?
Along the same lines, I am thinking what the need for the API Key is needed if the secret itself has identifying information. More than likely, I'm missing something here or more APIs would do it this way.
You don't need to suffer creating this mechanism by your own, you could just use OAuth for this. Actually by reading how OAuth works, I'm pretty sure that you'll get an overall idea of what the "API Key" is doing.
Long story short. OAuth allows you to create access tokens that will be requested by your users, once the user has asked for an access token, he'll be able to use it to get authenticated on the API.
You can also configure the duration for these access tokens, for example, let's say that you only want them to be valid for one hour. Then the user will use a new access token every hour, helping you to minimize risks against compromised access tokens.
If you want to take a look at the pipeline used by OAuth, it will be something like this:
The user sends an identifier and a shared secret (see them as username and password). If the identifier and the secret are correct, he'll receive a "refresh token", this token will be used to send requests to the token server to receive new "access tokens". The client sends a request to the tokens server to receive an access token, and now he'll be able to send requests to your API, where he'll use his access token as an identifier, and only if the token is valid, he'll get access to your application.
Maybe you could be curious about expired tokens, for example, What happens when the token has expired? Now our user needs to repeat all process again? No, because if the token has expired, he can just send a new request to the tokens server, sending his refresh token, and he'll get a new token to be used with your API.
I'm pretty sure that you already noticed that your API key is the "access token" equivalent, and your shared secret is the equivalent to the credentials used at the beginning of the OAuth process.
You can create your own mechanism, but you will need to take a lot of considerations that are already covered by OAuth. For example, Will you expire your API keys? After all, you should not trust a single key to be sent over every request for an undetermined amount of time. How will you handle the process to request new keys? Do you really want your users to send their secret every time they want a new key? Refresh tokens are useful for this.

Generating a new client secret

Is there a way to change the OAuth2 client secret for our Google app without changing the client ID?
I would like to change the client secret as a security best practice (e.g. when one of our production sys admins leaves the company) without having to get all our clients to re-authorize our app.
All I've found on this forum is how to generate client IDs and secrets for new applications. From what I can see, the only option is to generate a new client ID and secret together, meaning any authorizations obtained with the old client ID are effectively useless.
Client id and Client secret are a pair, together they are used to create the Refresh token and access tokens that allow your application to access a users data. If you where to only change the client secret then the refresh token and access token generated wouldn't match the old one. But any way you can't just change one.
You can create a new client id and Client secret pair for your application and then delete the old one. But the draw back to this will be that any one that had previously given your application access to there data will be forced to reauthenticate because there current refresh token will no longer work.
While I applaud your sense of security and desire to protect your customers data. There is a fine line between annoying customers and protecting them. I wonder how big of a chance there is that this person actually stole a bunch of refresh tokens as well as the client id and Client secret for your application? I also wonder what kind of access your application has and what the damage your former employee could do with the information they may or may not have stolen. Will it be worth it for them to create a new application to use the refresh token and application credentials?
You need to judge if its worth bothering your customers and forcing them to reauthenticate your application every time someone leaves the company.
Josh from the AdWords team directed me to the "Return to original console" link in the bottom right corner. In that version of the console you are able to reset client secrets.
See https://groups.google.com/forum/#!topic/adwords-api/twf3O3fg1oA for the cross posting.