Background
You may have come across API access_tokens with validity ranging from few minutes to few hours. Likewise you may have seen refresh_tokens with validity ranging from few days to last even up to an year.
As an API provider how do you determine the token expiration time?
Like other things in engineering, there are tradeoffs involved and constraints to keep in mind when making a decision.
Having a smaller validity limits the risk exposure when a token is lost or stolen. However smaller the expiry period, more frequent refreshes are needed resulting in increased load on the authorization server. Since there is a tradeoff involved, the goal is to identify a middle path which is reasonable from both security and server load standpoint.
Note: The next section has some suggestions on what could be good values to use but the good values may change depending on your context and constraints.
Thought and suggestions
Expiry period of access_token
- 5 mins might be too low and 60 min may be on the higher side. 15 min might be a good tradeoff.
Expiry period of refresh_token
-
Security best practices suggest keeping the expiry period of access_token and refresh_token the same and rotating refresh tokens along with access_tokens. Which means any attempt to reuse refresh_token can be detected and appropriately handled at the backend. It is the responsibility of the client to keep track of access_token expiry and refresh the tokens before the expiry. While it may sound like more work for clients, the refresh logic can be built into the client side libraries/SDK without burdening the developers with it.
-
For APIs which are not very security sensitive, it may be OK to have refresh_tokens with larger expiration time like 12 hours or 24 hours. In such cases the client doesn’t have to refresh access_tokens aggressively but can do so when it attempts to use the access_token and finds that it has expired. A larger expiration value means less load on the server but also means that the client needs to be careful while storing the refresh token. This is not a concern for native apps but something that browser based clients need to think through. Security teams don’t like seeing refresh tokens with large expiration value kept in browser.
Should API clients get to configure token expiration time?
Allowing for configurable expiry of tokens gives flexibility to API clients but adds to the complexity of the server implementation as well as of intermediate components that cache the tokens based based on expiry. The second issue with client configurable token expiry is that, it allows them to set arbitrarily large expiry period to simplify client / app implementation but inadvertently create security risks because of the long-lasting tokens.
Unless someone is building a general purpose authorization server which will be used in drastically different contexts, it is better to be opinionated about the expiration period based on the use-cases being enabled and not make the expiration period configurable by clients.
Revocation of tokens
Having the ability to revoke tokens allows limiting risk exposure in the event of a token getting compromised and the compromise being detected. However implementing revocation of the token may or may not be possible based on other design considerations and might require costly design changes to make it feasible. Note that this is also related to the expiry period of the token. Short lived tokens don’t need elaborate revocation mechanisms because they get expired at short intervals. Whereas allowing for long-lived tokens necessitates recovery mechanisms especially for powerful tokens.
Should access_token be revocable?
-
If the expiry period is short (say upto 15 mins) then it is not necessary to implement revocation. As the expiry period increases, the damage risk exposure of the compromised token increases. Further it may be noted that exposing JWT tokens directly to clients makes them irrevocable till expiry. However if a phantom token approach is used, where an opaque token is handled to the client and at the API gateway it is exchanged for an internal JWT token, then its feasible to implement revocation by deleting the external token to internal token mapping or marking it revoked.
-
Note that it’s hard to detect compromise of an access_token because by design it is multi-use. So unless there is a mechanism to detect compromise of access_token, there is not much use in having revocation mechanism.
Should refresh token be revocable?
-
The refresh_token is more powerful than access_token because it can be used to progressively generate more access and refresh tokens. Also unlike access_tokens, it’s possible for authorization server to detect re-use and revoke it if needed.
-
It is highly desirable to detect re-use of refresh_token and upon detection revoke the token chain (all refresh and access tokens linked to it). This also implies that refresh_tokens must be single/one-time use.