Logo
Home

OAuth token management done the right way

Introduction to token management

As APIs and integrations have become increasingly important in today’s digital landscape, token management is critical to a secure and reliable integration design. In this article, we’ll provide an overview of token management, including implementation considerations and best practices.

Token management encompasses the generation, storage, usage, refreshing, and revocation of tokens. These tokens grant us access to protected resources, such as financial transactions or reports housed inside a customer’s QuickBooks Online (QBO) account.

We generally interact with three types of tokens on the Intuit Developer Platform:

1. Access token

This is also referred to as a bearer token. We pass this in the Authorization header of requests each time we call Intuit APIs. It follows this syntax:

Authorization: bearer {accessToken}

Characteristics:

  • Access tokens are valid for one hour.
  • If an API request returns a 401 unauthorized error, it likely means the access token has expired.

2. Refresh token

We use this token to refresh an access token. To do so, we send a request to the token_endpoint and pass the refresh token in the body.

Characteristics:

  • Refresh tokens are valid for 100 days. This is a rolling expiry date that is extended each time the token is used to refresh an access token.

3. ID token

This standardized feature of OpenID Connect is used for sharing identity assertions. After being validated and decoded, the payload will contain data such as the aud (audience identifier) and sub (unique identifier for the user).

Characteristics:

  • We’ll receive this token post-handshake if OpenID scopes were requested in the authorization request.
  • Our app needs to validate all ID tokens we receive.

Implementation considerations

https://www.mydemoapp.com/oauthcallback?
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
state=kc913_security_cr239rklafka7ff324f24f2clpa9i08457macl138gnascac3&
realmId=1231434565226279

After receiving the authorization code and realmID, you’ll want to do a few things:

  1. Check that the state value in the server response matches the value you sent in the initial request.
  2. If it does, copy the code and realmId received in the server response.
  3. If it doesn’t, disregard the server response entirely. This a necessary step to ward against cross-site request forgery (CSRF).

With the code value in hand, exchange the authorization code for tokens by raising a server-to-server request to the token_endpoint and passing the authorization code in the body like this:

POST https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer HTTP/1.1
Accept: application/json
Authorization: Basic UTM0dVBvRDIwanp2OUdxNXE1dmlMemppcTlwM1d2
    NzRUdDNReGkwZVNTTDh0WEJlR3dheEtZSlVNaXaFg3ZlFlRzFtN2szTFRwbw==
Content-Type: application/x-www-form-urlencoded
Host: oauth.platform.intuit.com
Body: grant_type=authorization_code&
code=L3114709614564VSU8JSEiPkXx1xhV8D9mv4x6sZJycibMUI&
redirect_uri=https://www.mydemoapp.com/oauthcallback

The server response will contain an access token, a refresh token, and if you requested OpenID Connect scopes, an ID token as well. An example response is as follows:

{
"token_type": "bearer",
"expires_in": 3600,
"refresh_token":"L311478109728uVoOkDSUCl4s8FDRvkU0RHe3WtZQuBq",
"x_refresh_token_expires_in":8640000,
"access_token":"eyJlbmMiOiJBMTI4Q0JDLUIiwiYWxnIjoiZ.....vw.ZS298t_udSlkfajxLfO9Q",
"id_token":"eyJraWQiOiJyNHA1U2JMMnFhRmVoRnpoajhnSSIsI.....J6KPOfLVe2UQ"
}

At this point, you’ll want to store the realmId (received earlier in the first response), access token, refresh token, and the refresh token expiry time (initially expressed in seconds). ID tokens are generally not stored since they are used to validate the identity of a user.

An example database table is as follows:

idingest_daterealm_idaccess_tokenrefresh_tokenrefresh_token_expiry
12024-05-25913012341234eyJlMi…kcz98QpeyJraQ…12k2024-09-02
22024-05-28450167671212yN1U2…28uVc0ZsJ6KOf…3kdlR2024-09-05
32024-05-299120678900218t_ufajx…9ckzZlo1NBoTIQ…9ckz2024-09-06

Best practices

Storage

Always store the latest values of an access token and a refresh token, even if the value of the refresh token hasn’t changed. This helps to ensure you won’t ever miss new values.

Relationships

Maintain an accurate relationship between a realmId and its related access and refresh token. An access token or a refresh token will only work for API requests to the realmId it was authorized against.

Encryption

When not in use, ensure tokens are encrypted at all times with a key that is stored elsewhere – e.g. as an environment variable.

Key/secrets vaults

One option is to use a key or a secrets vault to store tokens. Many of the popular cloud options offer envelope encryption as an additional security measure.

Refreshing tokens nearing expiration

If a refresh token is nearing the expiration date, consider refreshing these proactively to ensure a delightful customer experience (assuming they relate to an active customer).

Token revocation

If a user wants to disconnect your app from their QuickBooks Online account, ensure you fully revoke the tokens by calling the revocation endpoint. This should be followed by a cleanup process in the relevant database table.

Token cleanup

If tokens expire or your app receives a disconnection request, consider cleaning up the tokens in your database.

SDKs