32

I have a basic doubt or apparently am missing out on something fundamental. When talking about an Android app that talks to the backend using APIs, the access to the resources/APIs are protected using access tokens and refresh tokens (much like OAuth 2.0).

From what I understand, this is how it works :

  1. The user open the app and provides his login credentials.
  2. App makes a POST request to the server and the server issues an access token (random, unguessable token) to the app.
  3. The app stores this access token securely on the local storage (sqlite db/shared preferences etc.) and uses sends this token with every other API call to let the server know that it is authorized to access the resource.
  4. Now this access token has an expiry time as well. So that even if the access token gets compromised, somehow, the attack window would be small.
  5. Now when this happens, it would require the user to renter his login credentials and obtain an authorized access token again, which at least in case of mobile apps, is a bad (not acceptable) user experience.
  6. So to solve this problem, there is a refresh token that is also issued to the app along with the access token in the first place. This refresh token is a very long lived special token, which makes sure that as soon as the access token expires, it requests the server for a new access token, thus removing the need for the user to re-enter his login credentials to retrieve a new authorized access token.

Now my question is:

how does this solve our original problem of preventing unauthorized access to the APIs ? In my opinion, it actually facilitates it further.

If the access token gets compromised, it's highly likely that the refresh token would also get compromised the same way, isn't it? And because the refresh token is a very long lived token, the attacker would be able to use it (till the refresh token does not expire) to keep generating new authorized access tokens. Is that correct ?

Please help me understand this.

qre0ct
  • 1,492
  • 3
  • 19
  • 30
  • Client_id and client_secret are also required with refresh tokens, right? – pri Feb 10 '16 at 10:43
  • Well yes, in the classic usage of OAuth 2.0, it should be required I guess. However, that would make sense in the case when we are exposing our APIs to third party developers. However, in case of our own mobile application which will be used by huge number of customers, it's not really used and instead the authorized access token is given on successful login. – qre0ct Feb 10 '16 at 11:13
  • @PriyankGupta No. There are two parameters to the refresh access token `POST`: `grant_type`, which value must be `refresh_token`, there is a `refresh_token` parameter, and finally, an optional `scope`. No `client_id` or `client_secret` when renewing an access token. See https://tools.ietf.org/html/rfc6749#section-6 – Alexis Wilke Aug 25 '17 at 22:54

1 Answers1

27

The main advantage of a refresh token is that it is easier to detect if it is compromised.

Consider these two scenarios:

  1. A single long-lasting auth token is used.
  2. A short duration auth token is used, and a long-lasting refresh token periodically requests a new auth token once the previous one has expired.

In scenario 1, if the auth token is compromised it would be hard for anyone to detect this, and the unauthorized access could continue indefinitely.

In scenario 2, if only the auth token is compromised (refresh token is not compromised too), it could only continue until the token expires.

In scenario 2, if the refresh token is compromised, once the refresh token is invoked, all other auth tokens that were generated using that refresh token are invalidated, so only 1 party can use the api (per refresh token) at a time. This results in multiple users repeatedly invalidating each other's auth tokens by generating new ones. The api could detect the breach because refreshes are being made prior to the auth token expiration, and would know to immediately revoke the refresh token.

TTT
  • 9,122
  • 4
  • 19
  • 31
  • The last paragraph of your answer was a little confusing, esp. the part "This results in multiple users repeatedly invalidating each other's auth tokens by generating new ones". Would really appreciate if you could please elaborate a little on this? – qre0ct Feb 11 '16 at 16:47
  • 4
    @geek_ji. Sure: it works like this: There is only 1 valid Auth token at any time (per refresh token). When the refresh token is used to get a new Auth token, all existing Auth tokens are invalidated, and a new one is handed out. If User 1 uses the refresh token to get a new Auth token, and now user 2 users the same refresh token to get a new Auth token, User 1's Auth token is no longer valid. User 1 now has to use the refresh token again to get a new Auth token, but in doing so invalidates User 2's token, etc. They are fighting over the auth token, and the API could detect it. – TTT Feb 11 '16 at 16:55
  • I tried to fit that explanation into a single comment. I'm not sure if that was any clearer... :D. – TTT Feb 11 '16 at 16:57
  • Great. I incorporated part of the explanation into the answer to make it clearer. – TTT Feb 11 '16 at 19:16
  • 1
    On second thoughts, I am still a little confused. I also went through http://security.stackexchange.com/questions/87119/how-secure-are-expiring-tokens-and-refresh-tokens for an understanding. We seem to be making a lot of assumptions here, like 1. the authorization server and resource servers are decoupled entities (which is not mandatory as per OAuth 2.0 principles, AFAIK) 2. The refresh token is strictly always exchanged with the authorization server alone and the connection between client and auth server is strictly HTTPS and the auth server is relatively uncompromisable. – qre0ct Feb 12 '16 at 06:59
  • So essentially we are assuming that refresh tokens are less susceptible to a compromise than the access tokens itself. Now as per your explanation above @TTT, if an attacker compromises a refresh token, he will try to obtain a new access token and because this request will be made even before the older access token, for that user, has expired, the auth server will be able to identify this and hence will expire the refresh token as well and thus not allow issuing of a new access token. But then if I am an attacker, from app behavior I would deduce the exact expiry time of access tokens – qre0ct Feb 12 '16 at 07:11
  • ( just by looking at when the app makes a hit for the API endpoint that fetches the new access token, unless the expiry time of the access token itself is not constant but random) and as an attacker I will always hit the API end point to receive the access token only after the above expiry time. I would thus always evade detection. – qre0ct Feb 12 '16 at 07:13
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/35631/discussion-between-geek-ji-and-ttt). – qre0ct Feb 12 '16 at 07:15
  • @geek_ji - regarding the link you provided, I agree with your assessment regarding separate connections for refresh vs normal access- that seems like a stretch to me. I agree with the point that a sniffer capturing for a short time is less likely to get the refresh token, but even that seems weak to me (in comparison to my answer). As for the attacker evading detection by waiting until the auth token expires, that is only true if the attacker is the only one using that refresh token. If you are also using it, then that's two refresh requests after expiration, and that can be detected. – TTT Feb 12 '16 at 14:55
  • @geek_ji: remember my previous explanation: The key is **there is only one valid Auth token at a time per refresh token.** So, my Auth token expires. I request a refresh and get a new one. Attacker requests a refresh a minute later which ruins my new token. Now my token I just got stops working. I request another refresh. Now attacker's token no longer works so he requests it again... and so on. We would constantly fight over who gets the auth token. The api could detect it one minute after expiration due to two refresh requests. – TTT Feb 12 '16 at 14:59
  • My understanding of OAuth is that the access token can not be invalidated which is why they should be short-lived. – Alex Oct 01 '19 at 20:06
  • @Alex - that is implementation specific. If you manage your own tokens you can invalidate them. – TTT Oct 01 '19 at 20:11
  • @TTT - AFAIK, you can only invalidate an access_token by storing them into a DB. But that obsoletes the idea behind token-based authentication. Another way to invalidate your token is by changing your SECRET_KEY. Am I missing something? – Anwar Hussain Oct 02 '19 at 14:26
  • @AnwarHussain - I agree that you'd need to use a token database to invalidate all access tokens for a specific user, but I wouldn't consider that idea "obsolete". The downside is that it adds latency to the validation process. If you're using signed tokens then it's harder to detect, but still possible, as the refresh token would be used more often than it should, and likely from multiple locations. – TTT Oct 02 '19 at 17:17