This answer has been put together by the help of two senior devs (John Brayton and David Jennes).
The main reason to use a refresh token is to reduce the attack surface.
Let's assume there is no refresh key and go through this example:
A building has 80 doors. All doors are opened with the same key. The key changes every 30 minutes. At the end of the 30 minutes I have to give the old key to the keymaker and get a new key.
If I’m the hacker and get your key, then at the end of the 30 minutes, I’ll courier that to the keymaker and get a new key. I’ll be able to continuously open all doors regardless of the key changing.
Question: During the 30 minutes, how many hacking opportunities did I have against the key? I had 80 hacking opportunities, each time you used the key (think of this as making a network request and passing the access token to identify yourself). So that’s 80X attack surface.
Now let’s go through the same example but this time let’s assume there’s a refresh key.
A building has 80 doors. All doors are opened with the same key. The key changes every 30 minutes. To get a new key, I can’t pass the old key (access token). I must only pass what's considered a refresh key (refresh token).
If I’m the hacker and get your key, I can use it for 30 minutes, but at the end of the 30 minutes sending it to the keymaker has no value. If I did, then the keymaker would just say "This token is expired. You need to send me a refresh token instead" To be able to extend my hack I would have to hack the courier to the keymaker. The courier has a distinct key (think of this as a refresh token).
Question: During the 30 minutes, how many hacking opportunities did I have against the refresh key? 80? No. I only had 1 hacking opportunity. During the time the courier communicates with the keymaker. So that’s 1X attack surface.
I did have 80 hacking opportunities against the key, but they are no good after 30 minutes.
A server would verify an access token based on credentials and signing of (typically) a JWT.
An access token leaking is bad, but once it expires it is no longer useful to an attacker. A refresh token leaking is far worse, but presumably it is less likely. (I think there is room to question whether the likelihood of a refresh token leaking is much lower than that of an access token leaking, but that’s the idea.)
Point is that the access token is added to every request you make, whereas a refresh token is only used during the refresh flow
So less chance of a MITM seeing the token
Frequency helps an attacker by making leaking slightly more possible.
- Heartbleed-like potential security flaws in SSL
- potential security flaws in the client,
- potential security flaws in the server
In addition, if the authorization server is separate from the application server processing other client requests then that application server will never see refresh tokens. It will only see access tokens that will not live for much longer.
Compartmentalization is good for security.
Last but not least refresh tokens can get rotated. Meaning 'a new refresh token is returned each time the client makes a request to exchange a refresh token for a new access token.'. As refresh tokens are continually exchanged and invalidated, the threat is reduced. To give you an example: Tokens are usually expired after a TTL usually an hour.
Refresh tokens not always, but often are revoked upon usage and a new one issued. Meaning if you ever have a network failure, when you're retrieving the new refresh token, then the next time you send that refresh token, it's considered revoked and you have to sign in.
For more on rotation see here and here
Summary
- Reducing Frequency
- Compartmentalization
- Rotation (quicker invalidation) and more granular management (expiration time or number of requests made) of tokens.
All help to to mitigate threats
For another take on this see this awesome answer
What refresh token is NOT about?
The ability to update/revoke access level through refresh tokens is a byproduct of choosing to use refresh tokens, otherwise a standalone access token could be revoked or have its access level modified when it expires and users gets a new token