10

That's something I've came across in a couple articles about OAuth 2: when it comes to persisting refresh tokens to database some authors prefer to store access token as well, or at least mention it as something you should do. And when it comes to granting access based on refresh_token a ticket is being picked up from database, deserialized, updated and sent to the user with a new refresh token.

Here is an example of RefreshTokens table, where ProtectedTicket column keeps serialized access_tokens issued to the user:

enter image description here

So far I can think of at least 3 reasons against this approach:

  1. Isn't it a security threat when you are keeping user's access tickets, just waiting for someone to grab them, and reuse for unsuspicious resource server? One-way hash can't be used, since we need to deserialize, update and send it back to the user, and we don't want to keep valid access tokens as well.

  2. For instance, you want to update encryption key used to serialize/deserialize your ticket once in a while just in case. If you don't want your users to be logged off once their access_token expires, you have to care about updating those persisted tickets.

  3. You have to write a chunk of code depending on how concerned you are about #1 and #2. Maybe even you implement some dirty hacks around you OAuth framework as it might not provide extensibility points you will need.

So the questions is, why do you want to do all that? What kind of advantage that should give to really make it worth all the hassle? Isn't it easier, safer and more maintainable just to make a brand new ticket once you've verified refresh_token?

7

What would be the point of hashing the accessToken?

We hash passwords because people reuse them everywhere. If they would not reuse passwords, we would not need to hash passwords, the application has been hacked after all (as the attacker gained access to the db), so all is already lost.

accessTokens are not reused. and adding to security, are only used once (for 10 minutes for example, depending on your token lifetime). So why would we need to hash them? RefreshTokens can be used to obtain multiple accesstokens, which is why it seems reasonable to hash those, but even that is disputable as refreshTokens are not used across applications.

If you really want, you might think about encrypting the accessTokens, but we suppose your entire application has been hacked, including the encryption key. By the way, you don't really store an accessToken, rather you store the ticket to obtain an accessToken, but that doesn't change the relevance of your question.

  • agree about most of the things, though the question was not about 'how to persist access tokens' but rather 'why persist them' – 2ooom Nov 10 '14 at 8:41
1

The answer is most likely related to performance.

OAuth2 access tokens are designed to be short-lived, whereas refresh tokens are designed to be longer-lived since they can be used to obtain new access tokens. Most client libraries are designed to cache the OAuth access token to avoid hitting the authorization server. See here:

https://github.com/google/google-api-dotnet-client/blob/master/Src/Support/GoogleApis.Auth/OAuth2/UserCredential.cs

/// <summary>
/// Default implementation is to try to refresh the access token if there is no access token or if we are 1 
/// minute away from expiration. If token server is unavailable, it will try to use the access token even if 
/// has expired. If successful, it will call <see cref="IAccessMethod.Intercept"/>.
/// </summary>
        public async Task InterceptAsync(HttpRequestMessage request, CancellationToken taskCancellationToken)
[...]

If you visit the Google OAuth2 playground, you can see some of this in action: https://developers.google.com/oauthplayground/

When you authorize an API (just try typing "profile" in for a custom scope and clicking 'Authorize APIs' if you don't want to click through the list), after you do the authentication exchange and receive an access/refresh token, you'll see the following:

"The access token will expire in [countdown] seconds.

[ ] Auto-refresh the token before it expires."

By caching or storing the access token, you prevent having to make a round trip to the authorization server to exchange the refresh token for an access token (protecting against latency and authorization server outages). Some servers may also rate limit how frequently you can exchange a refresh token for an access token (generating an access token may involve an "expensive" cryptographic operation on their part, for example).

Leaking the access token is "bad" in the sense that it can be used without any other information in order to assert the identity of the person who granted it - but it's mitigated somewhat by the fact that access tokens have limited lifespans, increasing pressure on the attacker to immediately tip their hand / use the values. Leaking the refresh token is (theoretically) "worse" since it would allow perpetual access, however what makes this more complicated is that doing a refresh <-> access token exchange also requires knowledge of your OAuth2 client_secret.

In the current model you describe, it's unclear whether ProtectedTicket is encrypted (you mention it's serialized, but later talk about updating persisted tickets). If you are encrypting access tokens in the database to protect them from (mis)use by those with administrative database access, you can look at solutions for dealing with versioned keys, which would allow you to rotate the encryption key. One I'm familiar with is https://github.com/google/keyczar, and someone has created .NET bindings for this (I'm assuming from your screenshot you are on .NET).

KeyCzar may provide a simple way to address some of your concerns, but a lot of the actual security properties of your system will depend on your threat model and many factors beyond the database schema.

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.