How to identify if the OAuth token has expired?

Solution 1:

Here's information on OAuth 2.0 token refresh.

Expires In Definition

The OAuth 2.0 standard, RFC 6749, defines the expires_in field as the number of seconds to expiration:

expires_in: RECOMMENDED. The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated. If omitted, the authorization server SHOULD provide the expiration time via other means or document the default value.

Token Refresh Handling: Method 1

Upon receiving a valid access_token, expires_in value, refresh_token, etc., clients can process this by storing an expiration time and checking it on each request. This can be done using the following steps:

  1. convert expires_in to an expire time (epoch, RFC-3339/ISO-8601 datetime, etc.)
  2. store the expire time
  3. on each resource request, check the current time against the expire time and make a token refresh request before the resource request if the access_token has expired

An example implementation is the Go oauth2 library which converts the expires_in value to a RFC 3339 date-time in the Token expiry property. expiry isn't defined by the OAuth 2.0 standard but is useful here.

When checking the time, be sure you are the same time, for example, using the same timezone by converting all times to epoch or UTC timezone.

In addition to receiving a new access_token, you may receive a new refresh_token with an expiration time further in the future. If you receive this, you should store the new refresh_token to extend the life of your session.

Token Refresh Handling: Method 2

Another method of handling token refresh is to manually refresh after receiving an invalid token authorization error. This can be done with the previous approach or by itself.

If you attempt to use an expired access_token and you get an invalid token error, you should perform a token refresh (if your refresh token is still valid). Since different services can use different error codes for expired tokens, you can either keep track of the code for each service or an easy way to refresh tokens across services is to simply try a single refresh upon encountering a 4xx error.

Invalid Access Token Errors

Below are some error codes from popular services:

  1. Facebook: Error 467 Invalid access token - Access token has expired, been revoked, or is otherwise invalid - Handle expired access tokens.
  2. LinkedIn: Error 401 Unauthorized.
  3. PayPal: Error 401 Unauthorized.

Implementations

The Zapier service is one service that implements the refresh after authorization error retry.

enter image description here

Refresh Token Expiration

If your refresh_token has also expired, you will need to go through the authorization process again.

The OAuth 2.0 spec doesn't define refresh token expiration or how to handle it, however, a number of APIs will return a refresh_token_expires_in property when the refresh token does expire. Different APIs will handle refresh token expiration differently so it's important to review the docs per API, but generally you may receive a new refresh token when you refresh your access token. Expiration should be handled in a similar way such as converting refresh_token_expires_in to a RFC 3339 date-time refresh_token_expiry value.

Some examples include LinkedIn, eBay, and RingCentral. In the LinkedIn API, when you refresh access tokens, you will receive a refresh token with a decreasing refresh_token_expires_in property targeting the original refresh token expiry time until you are required to auth again. The RingCentral API will return refresh tokens with a static time so the user does not have to auth again if token refreshes and refresh token updates are done consistently.

Solution 2:

Would recommend Method 2 above since a 401 can happen for multiple reasons such as renewing a token signing certificate or clock differences:

  • Check for a 401 after every API request
  • Get a new token - once only
  • Retry the API request - once only

I've implemented plenty of successful OAuth clients and have always used this technique - and avoided ever reading the expires_in field in my client side code