How bad is it when my OAuth2.0 tokens will leak? - oauth-2.0

I'm going to store user's OAuth2.0 tokens from various sites like Github. If my database leaks (which I hope it will not), how bad is this for the users? Will attackers have full access to their accounts? Revoking all access tokens will be my first step, but I just wanted to know.

Define bad!
Generally the attacker would not have full access to the accounts as tokens generally only offer a limited (scoped) amount of access anyway.
You mention access tokens. You generally wouldn't store access tokens long term as they should be short-lived. You would store refresh tokens though, as they are your means to getting future access tokens without the need of a user.
Access Tokens.
If you are storing access tokens and someone gains access to them it would mean that they could make use of any token for its lifetime (which isn't usually very long - often an hour or two) so it's bad in the sense that they are usable by anyone (if they are bearer tokens which most are).
If the bearer tokens are reference tokens, or encrypted value tokens, then there's the possibility that the attacker wouldn't know how to use them anyway before they expire. (i.e. they may not know the intended audience of the token).
If the access token is long lived and the attacker knows which resource server it's intended for, then the attacker could potentially use that token and in some cases it will not be possible to revoke the token anyway, so that's quite bad.
Refresh Tokens.
On their own refresh tokens in the wrong hands are not usable. If however the attacker is able to find out your client id and secret, then they could potentially create new tokens. You'd certainly want to revoke refresh tokens if you can.

Related

OAuth: Should an unexpired access token be revoked when it is refreshed?

Typically an access token is refreshed (using a refresh token) when it is expired. However, it's possible to refresh an unexpired token. I understand the requirements for revoking the refresh token as part of this process, but what I can't make out from the specification is whether the associated access token should be revoked.
From the oauth2 spec, as far as I can tell this is indeed not required. This has some advantages because it lets you do a refresh before your original access token expired, and you can continue to use this token until you get a fresh one.
tl;dr: No I don't think it's need to expire them, and I think this is by design.
It would be a nice feature to make access tokens revokable. But it's quite hard to implement in practice, assuming the system needs high availability and scalability.
There are two main options how access tokens are managed.
First is via a central database. In that case, to validate a token, this database has to be queried. With such central database, it's quite easy to revoke any tokens. But the problem is that this central storage is hard to scale and keep available. It is very rarely when this type of solution is used in practice.
The second approach is to have a self-contained access token. This is by far the most common approach. Such token can be validated without talking to a central storage/service. This makes the system truly scalable and available.
The problem with the second approach is that there is no way to revoke an access token. This is the trade off we do - scale/availability vs revocation support.
Systems tend to mitigate the absence of revocation by making TTL for access tokens very short. Hence, these systems may block access token being refreshed.

Why use JWT refresh token

I'm not sure I understand the concept of refresh tokens. I know what they do - store them somewhere and whenever the access token expires, get a new access token with them.
It is obviously very important to not leak this refresh token because otherwise a third party could obtain a new access token with it. Therefore it need to be kept extra safe.
My question is: Why not just keep a long lived access token extra safe? Where is the difference in security?
Here is how this fact is described by auth0.com e.g.:
Benefit: Shorter windows of access for leaked access tokens (these expire quickly, reducing the chance of a leaked token allowing access to a protected resource)"
That does not make any sense to me. So the access token expires quickly and therefore it is "not bad" if it is leaked.
On the other hand it is very bad if the refresh token is leaked. So why not just try to keep the access token as safe as the refresh token and have the exact same outcome but one less token to manage?
Sometimes it helps to think of the other side of the problem, e.g. the token issuer, not the token owner.
Example
Imagine someone's account has been removed / blocked by administrators.
With a token system, there is no way of invalidating all current tokens - the main point of JWT-style tokens is that possession of a valid token avoids centralised checks (in fact, the same is true of session cookies too really).
Problem with single token system
So to make this more efficient / convenient, in a single-token setup the lifespan of that token is sometimes quite large, meaning that owner (bearer) can have access for hours or days. Oh dear.
Solution: refresh token
A refresh token system, as they Auth0 guide said, allows this normal lifespan to be reduced (e.g. to minutes or seconds) before a refresh needs to be done. At this point, the server / centralised control can check if that account has been blocked or permissions are still good, and issue a new access token accordingly. It's still long enough to provide the performance gains of not calling the auth flow all the time (and of course not sending credentials)
Another use-case
A similar use case is the user losing a phone / device and they need to (effectively) revoke the token it had.
Hope that helps a bit.

What is the issue for long lived access tokens from the password grant?

Is there any security reason why I can't set the access tokens issued through password grant to 30 days?
If it's not a bad idea, then what should I do to mitigate the situation? For example,
It could be stolen, but that's the same as your password.
I could add a GUI to allow revoking of access tokens issued to mitigate 1.
I can ensure all previous access tokens are revoked after a password change.
It is not advisable to have long lives access tokens. Yes that's because of the fact that they could be stolen.
It could be stolen, but that's the same as your password.
Stealing access token is better than stealing password. This is what OAuth 2.0 tries to solve. Usually user passwords are commonly used (ex:- Same password for Facebook and email account). Thus stealing one has more security concerns. But yet stealing an access token is bad. Limiting its lifetime is one way to mitigate the risk.
I could add a GUI to allow revoking of access tokens issued to mitigate 1.
You could, but by the time you detect this, it could be too late.! For example 30 days is lots of time and malicious party can obtain everything under it's scope.
I can ensure all previous access tokens are revoked after a password change.
By default this must be done.! So this is not a solution for your scenario but a standard practice.
A solution ?
Use refresh tokens to refresh expired access tokens. Usually refresh token has an extended life-time. Unlike access token, you will use it rarely thus if you store it securely, you can protect it. Also, if your client is of type confidential, then you add another level of protection. So short lived access tokens and long lived refresh tokens is a better solution.

Oath 2.0 Why have tokens expire?

I am creating an Oath 2.0 system on my server allowing users to log into their account on my server from the app without having to give the username and password to the app itself. Which as I understand is the purpose of Oath, and it seems to work pretty well, the system is built on compliance with all Oath 2.0 specifications and is fully functional. But what I don't understand is why I have to have tokens expire... I mean I provide a refresh uri and they can easily at any time and at no cost renew the token (or get a new valid one). I dont see any purpose in this, why not just make the token never expire. I don't see the security benefits or any purpose for that matter for token expiration. Can someone explain to me why I have to have my tokens expire and why they can't just be good indefinitely?
In a word, for more safe.
In your question, you said at no cost renew the token, actually, when you refresh token, you need to authenticate with the authorization server(provide your client credential). So refresh token is not equal with access token. It can not give you the access to resource.
Why have token expire?
As OAuth 2.0 Threat Model and Security Considerations says:
3.1.2. Limited Access Token Lifetime
The protocol parameter "expires_in" allows an authorization server
(based on its policies or on behalf of the end user) to limit the
lifetime of an access token and to pass this information to the
client. This mechanism can be used to issue short-lived tokens to
OAuth clients that the authorization server deems less secure, or
where sending tokens over non-secure channels.
5.1.5.2. Determine Expiration Time
Tokens should generally expire after a reasonable duration. This
complements and strengthens other security measures (such as
signatures) and reduces the impact of all kinds of token leaks.
Depending on the risk associated with token leakage, tokens may
expire after a few minutes (e.g., for payment transactions) or stay
valid for hours (e.g., read access to contacts).
I found another use for it. When I store a token in my database at every login. If someone no longer uses a device or deletes their token (uninstalls an app or clears a cache) for any reason without properly "logging out" (logging out removes it from the database). Then there is a token stored on the database that will never be used again. After a while this becomes cumbersome taking up valuable space on the database and slowing down query executions for unused tokens. With token expirations I can run a cron job to scan the database for expired tokens every 15 minutes or so and remove them. Having to refresh tokens does put some strain on the server and the client but not as much as having potentially millions of unused tokens.

Why do access tokens expire?

I am just getting started working with Google API and OAuth2. When the client authorizes my app I am given a "refresh token" and a short lived "access token". Now every time the access token expires, I can POST my refresh token to Google and they will give me a new access token.
My question is what is the purpose of the access token expiring? Why can't there just be a long lasting access token instead of the refresh token?
Also, does the refresh token expire?
See Using OAuth 2.0 to Access Google APIs for more info on Google OAuth2 workflow.
This is very much implementation specific, but the general idea is to allow providers to issue short term access tokens with long term refresh tokens. Why?
Many providers support bearer tokens which are very weak security-wise. By making them short-lived and requiring refresh, they limit the time an attacker can abuse a stolen token.
Large scale deployment don't want to perform a database lookup every API call, so instead they issue self-encoded access token which can be verified by decryption. However, this also means there is no way to revoke these tokens so they are issued for a short time and must be refreshed.
The refresh token requires client authentication which makes it stronger. Unlike the above access tokens, it is usually implemented with a database lookup.
A couple of scenarios might help illustrate the purpose of access and refresh tokens and the engineering trade-offs in designing an oauth2 (or any other auth) system:
Web app scenario
In the web app scenario you have a couple of options:
if you have your own session management, store both the access_token and refresh_token against your session id in session state on your session state service. When a page is requested by the user that requires you to access the resource use the access_token and if the access_token has expired use the refresh_token to get the new one.
Let's imagine that someone manages to hijack your session. The only thing that is possible is to request your pages.
if you don't have session management, put the access_token in a cookie and use that as a session. Then, whenever the user requests pages from your web server send up the access_token. Your app server could refresh the access_token if need be.
Comparing 1 and 2:
In 1, access_token and refresh_token only travel over the wire on the way between the authorzation server (google in your case) and your app server. This would be done on a secure channel. A hacker could hijack the session but they would only be able to interact with your web app. In 2, the hacker could take the access_token away and form their own requests to the resources that the user has granted access to. Even if the hacker gets a hold of the access_token they will only have a short window in which they can access the resources.
Either way the refresh_token and clientid/secret are only known to the server making it impossible from the web browser to obtain long term access.
Let's imagine you are implementing oauth2 and set a long timeout on the access token:
In 1) There's not much difference here between a short and long access token since it's hidden in the app server. In 2) someone could get the access_token in the browser and then use it to directly access the user's resources for a long time.
Mobile scenario
On the mobile, there are a couple of scenarios that I know of:
Store clientid/secret on the device and have the device orchestrate obtaining access to the user's resources.
Use a backend app server to hold the clientid/secret and have it do the orchestration. Use the access_token as a kind of session key and pass it between the client and the app server.
Comparing 1 and 2
In 1) Once you have clientid/secret on the device they aren't secret any more. Anyone can decompile and then start acting as though they are you, with the permission of the user of course. The access_token and refresh_token are also in memory and could be accessed on a compromised device which means someone could act as your app without the user giving their credentials. In this scenario the length of the access_token makes no difference to the hackability since refresh_token is in the same place as access_token. In 2) the clientid/secret nor the refresh token are compromised. Here the length of the access_token expiry determines how long a hacker could access the users resources, should they get hold of it.
Expiry lengths
Here it depends upon what you're securing with your auth system as to how long your access_token expiry should be. If it's something particularly valuable to the user it should be short. Something less valuable, it can be longer.
Some people like google don't expire the refresh_token. Some like stackflow do. The decision on the expiry is a trade-off between user ease and security. The length of the refresh token is related to the user return length, i.e. set the refresh to how often the user returns to your app. If the refresh token doesn't expire the only way they are revoked is with an explicit revoke. Normally, a log on wouldn't revoke.
Hope that rather length post is useful.
In addition to the other responses:
Once obtained, Access Tokens are typically sent along with every request from Clients to protected Resource Servers. This induce a risk for access token stealing and replay (assuming of course that access tokens are of type "Bearer" (as defined in the initial RFC6750).
Examples of those risks, in real life:
Resource Servers generally are distributed application servers and typically have lower security levels compared to Authorization Servers (lower SSL/TLS config, less hardening, etc.). Authorization Servers on the other hand are usually considered as critical Security infrastructure and are subject to more severe hardening.
Access Tokens may show up in HTTP traces, logs, etc. that are collected legitimately for diagnostic purposes on the Resource Servers or clients. Those traces can be exchanged over public or semi-public places (bug tracers, service-desk, etc.).
Backend RS applications can be outsourced to more or less trustworthy third-parties.
The Refresh Token, on the other hand, is typically transmitted only twice over the wires, and always between the client and the Authorization Server: once when obtained by client, and once when used by client during refresh (effectively "expiring" the previous refresh token). This is a drastically limited opportunity for interception and replay.
Last thought, Refresh Tokens offer very little protection, if any, against compromised clients.
It is essentially a security measure. If your app is compromised, the attacker will only have access to the short-lived access token and no way to generate a new one.
Refresh tokens also expire but they are supposed to live much longer than the access token.
I've written a little about this because I was pondering the reasoning myself today.
https://blog.mukunda.com/cat/2023/refreshing-access-tokens.txt
Essentially, I think the main security boost is only there if the refresh token does not remain the same over its lifetime.
Let's say someone steals your tokens from your browser cookies because they had access to your device temporarily.
If they use the refresh token, and the refresh token changes, then you have feedback – you are logged out. That can seem rightfully suspicious to careful users who can then take action and revoke all tokens.
If the refresh token doesn't update upon each use, then it is harder to notice that someone has access in tandem. (Chances are, if does update, then it might update from your device automatically before the attacker can even get to use it.)
If the refresh token does not get updated each time you use it, then I don't see any boost in security from the strategy, since it will be right next to the access token and client secrets.
So, why access tokens? It is so you can check that your credentials are valid regularly.
Do refresh tokens expire? Yes, but usually after a few months if you have "remember me" ticked. There's no expiration time in the spec, so you just go until it fails. Services that require longer unmonitored sessions might have secret credentials so they can refresh their refresh token.
Update:
I also glossed through the OAuth 2.0 specification and see the same reasoning, though it emphasizes that the invalid authentication feedback can be caught on the server side. That is a great point – the server can automate revoking the token if it is compromised.
If a refresh token is compromised and subsequently used by both the attacker and the legitimate client, one of them will present an invalidated refresh token, which will inform the authorization server of the breach.

Resources