Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Caching the access token on oauth or not?

Tags:

java

oauth

I am currently implementing an authentication using oauth2 with Google.

I've read that I should cache the access token for later, but do I really need to do this?

I thought about storing it encrypted within the session. If it expires, I'll get a new token.

Also if I need to cache the token, how do I know to which user it belongs?

like image 941
Christian Avatar asked Dec 15 '15 17:12

Christian


2 Answers

I've read that I should cache the access token for later, but do I really need to do this?

Yes, that what is OAuth made for. The access token is needed to give your app access to a resource at the service provider without providing username and password every time.

I thought about storing it encrypted within the session. If it expires, I'll get a new token.

It looks like you mixed up things here. The expiration of a session and of an access token are different things. The access token has usually a far longer life time then a session has (e.g. token: 60 minutes vs session: 15 minutes).

If an access token expires, you need the refresh token to get a new access token. If you don't have a refresh token, you have to initiate a grant flow again to get a new access token.

Also if I need to cache the token, how do I know to which user it belongs?

That's your responsibility to maintain that connection in your DB somewhere. The service provider (in your case Google) does the same on their end, in order to match the access token to an user/resource. Regarding your 2nd point: you should also store the refresh token.


I suggest you have read here: Why is OAuth designed to have request token and access token?

like image 66
Carsten Hagemann Avatar answered Sep 25 '22 19:09

Carsten Hagemann


You should definitely cache your access tokens. Generating access tokens is expensive, and usually they come with a relatively long expiration time, therefore they can be reused many times, avoiding bombarding the auth server with new requests every time.

As an example, here is a very simple implementation of a cache in Scala. A class implementing your oauth operations (getToken, refreshToken, etc.)

class authHandler private(serviceURL: java.net.URL) {

  def getToken(clientId: String,
               clientSecret: String,
               scope: String,
               resource: String = ""): Future[String] = {

    val cacheKey = clientId + scope

    S2SAuthHandler.getTokenFromCache(cacheKey) match {
      case Some(tk) => Future(tk)
      case None => requestTokenFromServer(clientId, clientSecret, scope, resource)
    }
  }

  private def requestTokenFromServer(clientId: String,
                                     clientSecret: String,
                                     scope: String,
                                     resource: String): Future[String] = {

        val authToken = <http request from server>

//expiration time is set to a few seconds less than the one provided from the server, to avoid returning an already expired token. 
        authToken.expires = authToken.expires - 5 + System.currentTimeMillis() / 1000  S2SAuthHandler.storeTokenToCache(clientId + scope, authToken)


    authToken.accessToken      
    }
}

and a companion object, implementing the cache. Companion objects in Scala are static, therefore you can create as many instances of your oauth handler class, still have one global cache available.

The cache is a simple map [key, token] where the key could be the "clientId + scope". You want to store different tokens per client and scope. The token should contain the access token per se, plus refresh token if available, expiration time, etc.

/** Companion objec  */
object authHandler {

  private val tokenCache = mutable.Map.empty[String, AuthToken]

  private def getTokenFromCache(cacheKey: String): Option[String] = {
    if ((tokenCache contains cacheKey) && (tokenCache(cacheKey).expires > System.currentTimeMillis / 1000)) {
      Some(tokenCache(cacheKey).accessToken)
    }
    else {
      None
    }
  }

  private def storeTokenToCache(key: String, tk: AuthToken) = {
    tokenCache(key) = tk

//Depending on your execution environment, I would recommend to encrypt the token before storing in the cache
   }
}
like image 40
Visiedo Avatar answered Sep 22 '22 19:09

Visiedo