24

In the comments of a question on StackOverflow, OAuth2 Why do access tokens expire?, people are questioning how secure refresh tokens are.

This comment is how I feel:

So it provides some protection from packet sniffing, as long as the intercept only catches ordinary data requests (Chuck only gets the access token)? That sounds a little weak; the black hat just has to wait for a bit until the user requests a new access token and then he'll get the client ID, secret, and refresh token.

Are we all missing something or basing our fears on an incorrect understanding?

Or is it correct that the security of short-lived access tokens and refresh tokens is based on the assumed probability of the sniffer running when a refresh occurs being 'unlikely'.

  • Could you edit your question title to something more detailled than "How secure is ...?". This type of question is by nature hard to answer and could refrain contributors from chipping in out of fear of having to write an entire essay on token-based auth. – Steve Dodier-Lazaro May 6 '15 at 12:33
  • Note that a request with the refresh token does NOT include the client_id and client_secret. The client_secret is only used when you do a server to server request for an access token. – Alexis Wilke Aug 25 '17 at 23:16
  • @AlexisWilke, pls clarify: Are you telling that requests with refresh_token from browser do not use client_secret, but from the relying party (RP) server include? My understanding is that client_secret only used for signing or encryption, but never included in request – Michael Freidgeim Aug 25 '17 at 23:55
  • @MichaelFreidgeim The refresh request is defined here: tools.ietf.org/html/rfc6749#section-6 -- it expects the grant_type, refresh_token and optionally a scope. Otherwise, you NEVER want to have your client_secret in the browser unless the user is logged in, otherwise it's not secret anymore. So... if you were to need the client_secret to be able to log in, you'd have a problem. – Alexis Wilke Aug 26 '17 at 0:29
14

It could be that the access token might end up being used around the application over plain HTTP connections. So if an attacker sniffed it, they would only have short term access. This is what used to happen on the web as standard. Login was over HTTPS if you were lucky, and the rest of your session was over plain HTTP, transmitting the session ID in cleartext.

The refresh token is only transmitted to the authorization server, so it is easier to enforce HTTPS only, meaning that an attacker could not eavesdrop on this connection.

See here for more information:

There is a security reason, the refresh_token is only ever exchanged with authorization server whereas the access_token is exchanged with resource servers. This mitigates the risk of a long-lived access_token leaking (query param in a log file on an insecure resource server, beta or poorly coded resource server app, JS SDK client on a non https site that puts the access_token in a cookie, etc) in the "an access token good for an hour, with a refresh token good for a year or good-till-revoked" vs "an access token good-till-revoked without a refresh token."

  • 4
    This is good point but could you please provide more clarifications on how we benefit from refresh token if authorization server and resource server are implemented in the same web application? Assumption is that traffic is HTTPS. – svlada Aug 9 '16 at 17:22
8

I answered a similar question that ended up being marked as a duplicate to this one. However, I feel that my answer to that question provides a stronger argument for how refresh tokens provide additional security. In short, if the refresh token is compromised, it is much easier to detect it and take appropriate action, such as disabling the auth tokens and refresh tokens, and forcing the user to login again with their credentials. In other words, compromised credentials can be shutdown much faster when refresh tokens are in use.

6

Let's consider there is a server that validates and issues tokens to a client.

Client (sends username & password) -> Server

Server (validates the credentials and returns access and refresh tokens) -> Client

The client stores the tokens securely and uses the access token for the further API calls made to the server (until the access token expires). Once the access token expires, the client may receive a 401(unauthorized) HTTP code from the server and realizes the access token is no longer valid.

The client then uses its refresh token and gets the new access and refresh tokens from the server.

Effects of a compromised access token - The attacker will be able to access the data until the access token expires.

Effects of a compromised refresh token - The attacker may be able to obtain a new access and refresh token which may also invalidate the victim's access. When the victim tries to get a new access token with their refresh token it will fail because their refresh token has already been used. The victim would have to log in again using their credentials which would reissue the tokens and invalidate the attacker's stolen tokens.

1

In addition to the accepted answer of the authentication provider being often a different server from the resource provider (thus having HTTPS required over the resource provider which might not), even in the case where they are both the same server with HTTPS it is better to have a short-lived access token and long-lived refresh token.

Think about it: how many places handle the refresh token? On the client or browser, it should be in a central place that looks up the current access token and if that has expired or the request fails, uses the refresh token instead (typically if your service provides an SDK, this is one small subset of that SDK which can be heavily reviewed for potential security vulnerabilities). On the authentication provider, it is only ever handled in the code path which handles the refresh_token grant type. If you want to prove that the refresh token is never sent to a log file or sent to an external repo, it is a pretty small and manageable collection of code you need to look through to verify that.

Conversely, the access token is used hopefully only in the one place on the client (again), but everywhere on the resource provider. Every HTTP request coming into your app has the header in the Authorization header. If you want to prove that the access token is never put into a log file, and that no one has put in malicious code to export your access tokens off to https://myaccesstokenfarm.example.com, that is a very large (bordering on impossible in some codebases) task.

The general security principle here is reduction of attack surface. Refresh tokens could be pulled from a man-in-the-middle attack just like an access token could be, but by restricting the attack surface to just one URL on one server and with just one executing code path, it is much easier to do everything in your power to make that particular resource secure.

As an arbitrary example, if you have HTTPS compression turned on, you might be vulnerable to BREACH attacks throughout your API; but you want compression on for efficiency, so you live with that possibility. On your authorization endpoint, however, you turn compression off and take the extra steps to ensure there are multiple layers of defenses against known attacks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.