How do I get started with my OAuth integration?
You need to create an app in order to have a container for the OAuth workflow. Only apps registered with the Intuit Developer portal can implement the OAuth workflow to access QuickBooks companies and the QuickBooks Online API. After registering your app, you receive a client ID and client secret: one set for use with sandbox environments and one set for use with production QuickBooks companies. See Creating an app for complete details.
What is a redirect URI and why is it required?

A redirect URI is the location in a third-party app where Intuit’s OAuth 2.0 service returns control at various junctures during the authorization process. Code at this location processes the initial authorization response, constructs the request for refresh and access tokens, and manages resulting refresh and access tokens. A developer registers one set of redirect URIs for the development environment and one set for the production environment on the Keys tab of the app’s dashboard. The image below showcases the location of both sets of redirect URIs on the app’s Keys tab.


The Intuit OAuth 2.0 service redirects users to registered URIs, only, which helps prevent some attacks. Any HTTP redirect URIs must be protected with TLS security; as a result, the service will only redirect to URIs beginning with https. This prevents tokens from being intercepted during the authorization process.

Within the development environment, an app registers a redirect URI for each 3rd party client wishing to gain access to the developer’s sandbox companies. Besides the app itself, such clients can include Postman, OAuth 2.0 playground, and so on.

What are refresh token and access token durations?
  • Access tokens are valid for 3600 seconds (one hour), after which time you need to get a fresh one using the latest refresh_token returned to you from the previous request. If a request to the QuickBooks Online API returns the message, 401 unauthorized, the access_token has expired.
  • The lifetime for the refresh_token returned with the initial access_token is set to 100 days.
  • Always use the current refresh_token when requesting a new access_token. A new refresh_token is returned and the previous refresh_token is expired. This new refresh_token now has a lifetime of 100 days.
  • If an access_token is not requested during the current refresh_token 100 day lifetime, the refresh_token expires and access to the QuickBooks company terminates.
  • As long as it hasn’t expired, the refresh_token can be reset as often as needed from the time the original access_token was generated.

Click here for complete details on refreshing the access token.

Why does my refresh token expire after 24 hours?
Stale refresh tokens expire after 24 hours. Each time you refresh the access_token a new refresh_token is returned with a lifetime of 100 days. The previous refresh_token is now stale and expires after 24 hours. When refreshing the access_token, always use the latest refresh_token returned to you.
What is the purpose of scopes?

A scope corresponds to a level of access to Intuit user data or QuickBooks company data. The OAuth 2.0 authorization request includes the list of scopes you require. We recommend requesting scopes as needed. It is generally a best practice to request scopes incrementally, at the time access is required, rather than up front. Each time you change the set of scopes you must initiate the authorization workflow again with the new list of scopes and you must get new access and refresh tokens. Current supported scopes include:

  • com.intuit.QuickBooks.accounting—QuickBooks Online API
  • com.intuit.QuickBooks.payment—QuickBooks Payments API
  • openid—OpenID Connect processing
  • profile—user’s given and family names
  • email—user’s email address
  • phone—user’s phone number
  • address—user’s physical address
How to mitigate against cross-site request forgery (CSRF) in authentication requests?

You must protect the security of your users by preventing cross-site request forgery (CSRF) attacks. To mitigate against these attacks, include a unique session token in the authorization request, via the state query parameter, that holds the state between your app and the user’s client. In turn, your app matches this unique session token with the one returned by the Intuit OAuth service in the authentication response to verify that the user, rather than a malicious attacker or bot, is making the request. These tokens are often referred to as cross-site request forgery (CSRF) tokens.

One good choice for a unique session token is a string of 30 or so characters constructed using a high-quality random-number generator. Another is a hash generated by signing some of your session state variables with a key that is kept secret on your back-end. Click here for more information.

What is the validity of OAuth2.0 Tokens ? How will it affect my App ?

With OAuth 2.0, you have two types of tokens for each user:

  • An access token, which you pass in the Authorization header with every API request, such as when you query CompanyInfo. The access token is short-lived, and expires after 1 hour.
  • A refresh token, which your app only uses to mint a new access token when the prior one expires. The refresh token can last up to 100 days before it expires, and then the user needs to sign in and grant consent again or you can get a new one programmatically using the Refresh Token API before it expires. Keep in mind that a refresh token is only for getting new (i.e., “refreshing”) access tokens; you can’t pass a refresh token for requests like querying CompanyInfo. Also, the actual value of a refresh token may change more frequently under certain circumstances–but this does not impact how often the user signs in. See Understand Token Expiration for more information.
What is invalid_grant? What are some invalid grant solutions?

This error can pop up during two of the following actions: (1) Exchanging your authorization code for bearer tokens, (2) Refreshing bearer tokens

If the error occurred during the exchange of the authorization code for the bearer token, please check the following:
  1. Check the ‘redirect URI’ configured in the apps’ Keys section. It should match with the Redirect URI used in the code. It should not have any query parameters. If query parameters are required, you can pass them as ‘state’ variables.
  2. QuickBooks OAuth server will send the ‘code’ to the Redirect URI specified in the developer’s application, please make sure the developer’s application is not using the same parameter name ‘code’ for other purpose.
  3. Check all the OAuth 2.0 keys used. Keys for the sandbox environment and production environment are different. Development keys should use Redirect URIs that are associated with development keys. Production Keys should use Redirect URIs that are associated with Production keys.
  4. Only exchange for bearer tokens ONE time. If two attempts are made to exchange for bearer tokens using your authorization code - the first attempt will succeed and the second attempt will return invalid_grant. On our side we see this as a possible security issue and will revoke your refresh tokens from the first successful call. Consequently your next attempt to refresh tokens will return ‘invalid_grant’ and you will need to start the authorization process from the beginning.
If the error occurred during refresh token call, please check the following:
  1. Check if the refresh token has expired. Based on the QuickBooks Online docs when refreshing the tokens a new refresh token may be returned to you. Thus, it is important to store both the access and refresh token each time a call is made to the token endpoint. If an old refresh_token is used to refresh your tokens, you will get an invalid_grant error.
  2. Check if the QuickBooks Online API has a service outage or is under maintenance by going to the status page. If there is a service outage, invalid_grant can also be returned.
  3. Check the code to see if the code is not sending any old cached values instead of the latest ones. If you are using QuickBooks Online SDKs, make sure the client object is updated with the latest token object.
  4. Make sure you are using the same refresh token from the last API call made to refresh the tokens. To avoid this error, as a standard practice make sure you store the latest access/refresh tokens in your database every time you make a Token Refresh API call.
  5. Make sure the refresh token is not revoked. Using a revoked token to refresh the tokens will result in this error.
  6. As seen in list item 4 above: the refresh token maybe be invalid because multiple attempts were made to exchange the authorization code for bearer tokens.