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 suppose there is no refresh key and let’s 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 access token. I must only pass the refresh key.
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 do, then the keymaker would just say "This token is expired. You need to refresh the token." 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. Heartbleed-like potential security flaws in SSL, potential security flaws in the client, and potential security flaws in the server all make leaking possible.
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 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