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
}
}