OpenID connect

This document explains how to implement Intuit single sign-on using Intuit’s OAuth 2.0 authentication implementation, which conforms to the OpenID Connect specification and is OpenID Certified. To explore this workflow interactively, experiment with the OAuth 2.0 playground.


To begin, obtain OAuth 2.0 client credentials by creating a new QuickBooks Online application in your Intuit Developer Account. Next define a Redirect URI in your app’s Keys tab where Intuit sends responses to your authentication requests. Then your client application authenticates the user by obtaining an ID token and validating it. At a high level, you follow the steps described in this page.

Download the OAuth Library

The language-specific examples on this page use QuickBooks Online API Client Libraries to implement OAuth 2.0 authentication using OpenID Connect. To run the code samples, you must first install the client library for your language.


When you use a QuickBooks Online API Client Library to handle your application’s authentication flow, the client library performs many actions that the application would otherwise need to handle on its own. The client library also generates correct redirect URLs and helps to implement redirect handlers that exchange authorization codes for access tokens.


The following client libraries integrate with popular frameworks, which makes implementing OAuth 2.0 authentication simpler. More features will be added to the libraries over time.



.NET

Java

PHP

Node.js

Python

1
Install-Package IntuitOAuth2PlaformClient

1
2
3
Download the latest version of oauth2-platform-api.jar and include it in your project.
Sample below shows how to add it to a gradle project:
compile (group: 'com.intuit.quickbooks-online', name: 'oauth2-platform-api', version: '4.0.3', classifier: 'jar-with-dependencies')

1
composer require quickbooks/v3-php-sdk

1
$ npm install intuit-oauth

1
$ pip install intuit-oauth
Obtain OAuth2 credentials for your app

Obtain OAuth 2.0 credentials such as a client id and client secret from the “keys” tab after creating a QuickBooks Online application in developer.intuit.com/myapps.


Define redirect URIs: Under the keys, you can define one or more redirect URIs. These URIs handle responses from the OAuth 2.0 server and are called after the user authorizes the connection. URIs in this list are the only ones to which the authorization response can be sent from the OAuth 2.0 server.


You must define at least one URI specifically for your application’s auth endpoint before you can use OAuth 2.0. For the sandbox environment, this list can include localhost. As a best practice, design your app’s auth endpoints in a way that doesn’t expose authorization codes to other resources on the page.

Authenticating the user

Authenticating the user involves obtaining an ID token and validating it. ID tokens are a standardized feature of OpenID Connect designed for use in sharing identity assertions on the Internet.


Obtaining the token requires an authentication step where the user logs in with their QuickBooks Online account after which the user is asked whether they are willing to grant the permissions that your application is requesting. This process is called user consent.


If the user grants the permission, the Intuit Authorization Server sends your application an authorization code at the callback endpoint that you defined in the Redirect URL section of the Keys tab of your app. This authorization code can be exchanged to obtain the access token and ID token.

Step 1: Prepare authorization request

Your first step is to create the authorization request with the parameters that identify your application and permissions that the user will be asked to grant to your application.


If you use one of our client library for OAuth 2.0, you create and configure an object that defines these parameters. If you call the Intuit OAuth 2.0 endpoint directly, you’ll generate a URL and set the parameters on that URL.


.NET

Java

PHP

Node.js

Python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Instantiate object
public static OAuth2Client auth2Client = new OAuth2Client(“clientid”, “clientsecret”, “redirectUrl”, “environment”); // environment is “sandbox” or “production”

//Prepare scopes
List<OidcScopes> scopes = new List<OidcScopes>();
scopes.Add(OidcScopes.OpenId);
scopes.Add(OidcScopes.Email);

//Get the authorization URL
string authorizeUrl = auth2Client.GetAuthorizationURL(scopes);

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//Prepare the config
OAuth2Config oauth2Config = new OAuth2Config.OAuth2ConfigBuilder("clientId", "clientSecret")
        .callDiscoveryAPI(Environment.SANDBOX) .buildConfig();

//Generate the CSRF token
String csrf = oauth2Config.generateCSRFToken();

//Prepare scopes
List<Scope> scopes = new ArrayList<Scope>();
scopes.add(Scope.OpenIdAll);

//Get the authorization URL
String url = oauth2Config.prepareUrl(scopes, redirectUri, csrf); //redirectUri - pass the callback url

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$dataService = DataService::Configure(array(
      'auth_mode' => 'oauth2',
      'ClientID' => "Client ID from the app's keys tab",
      'ClientSecret' => "Client Secret from the app's keys tab",
      'RedirectURI' => "The redirect URI provided on the Redirect URIs part under keys tab",
      'scope' => "OpenID Scope",
      'baseUrl' => "Development/Production"
));
$OAuth2LoginHelper = $dataService->getOAuth2LoginHelper();
$authorizationCodeUrl = $OAuth2LoginHelper->getAuthorizationCodeURL();

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Instance of client
var oauthClient = new OAuthClient({
    clientId: '<Enter your clientId>',
    clientSecret: '<Enter your clientSecret>',
    environment: 'sandbox',                      // ‘sandbox’ or ‘production’
    redirectUri: '<Enter your redirectUri>'
});

// AuthorizationUri
var authUri = oauthClient.authorizeUri({scope:[OAuthClient.scopes.OpenId]});  // can be an array of multiple scopes ex : {scope:[OAuthClient.scopes.Accounting,OAuthClient.scopes.OpenId]}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//Instantiate client
auth_client = AuthClient(
    “client_id”,
    “client_secret”,
    “redirect_uri”,
    “Environment”, # “sandbox” or “production”
)

// Prepare scopes
scopes = [
    Scopes.OPENID,
    Scopes.EMAIL,
]

// Get authorization URL
auth_url = auth_client.get_authorization_url(scopes)
HTTP/REST

Retrieve the base URI from the discovery document using the key, authorization_endpoint. The discussion here assumes the base URI (https://appcenter.intuit.com/connect/oauth2) that includes the following parameters:


Field Description
client_id

Required. Identifies which app is making the request. Obtain this value from the Keys tab on the app profile via My Apps on the developer site. There are two versions of this key:


  • Development key—use only in the sandbox environment.
  • Production key—use only in the production environment.
scope

Required. A space-delimited list of scopes that identifies the QuickBooks Online API access that your application is requesting. The values passed in this parameter inform the consent screen that is shown to the user. Available scopes include:


  • 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
redirect_uri Required. Determines where the API server redirects the user after the user completes the authorization flow. The value of this parameter must exactly match one of the values listed for this app in the app settings. This includes the https scheme, the same case, and the trailing ‘/’. For the sandbox environment, this list can include localhost (no HTTPS with localhost). IP addresses are not allowed for redirect URIs.
response_type Required. Determines whether the Intuit OAuth 2.0 endpoint returns an authorization code. Always set this to code
state Required. Specifies any string value that your application uses to maintain state between your authorization request and the authorization server’s response. The server returns the exact value that you send as a name-value pair in the request. To mitigate against cross-site request forgery (CSRF), it is strongly recommended to include an anti-forgery token in the state, and confirm it in the response.
Step 2: Redirect to Intuit’s OAuth 2.0 server

Redirect the user to Intuit’s OAuth 2.0 server using the URL prepared above to initiate the authentication and authorization process. This step is required when your application first needs to access user’s data. In the case of incremental authorization, this step also occurs when your application first needs to access additional resources that it does not yet have permission to access.


.NET

Java

PHP

Node.js

Python

1
2
// Redirect the authorization URL
return Redirect(authorizeUrl);

1
2
Use standard url redirect-
resp.sendRedirect(url);

1
2
//redirect users to authorization screen url
header('Location: '. $authorizationCodeUrl);

1
2
// Redirect the authUri
res.redirect(authUri);

1
2
//Using standard redirect
return redirect(auth_url)
HTTP/REST

Here is an example of a complete authorization request URI specifying the openid and email scopes, with line breaks and spaces for readability

1
GET https://appcenter.intuit.com/connect/oauth2?client_id=Q3ylJatCvnkYqVKLmkH1zWlNzNWB5CkYB36b5mws7HkKUEv9aI&response_type=code&scope=openid%20email&redirect_uri=https://www.mydemoapp.com/oauth-redirect&state=security_token%3D138r5719ru3e1%26url%3Dhttps://www.mydemoapp.com/oauth-redirect&state=security_token%3D138r5719ru3e1%26url%3Dhttps://www.mydemoapp.com/oauth-redirect&

In this step, the user decides whether to grant your application the requested access. At this stage, Intuit displays a consent window that shows the name of your application and the QuickBooks Online Company name that it is requesting permission to access with the user’s authorization credentials. The user can then consent or refuse to grant access to your application.

View Screenshot

qbo/docs/develop/authentication-and-authorization/openid_connect.png

Your application doesn’t need to do anything at this stage as it waits for the response from Intuit’s OAuth 2.0 server indicating whether the access was granted. That response is explained in the following step.

Step 4: Handle the OAuth 2.0 server response

The OAuth 2.0 server responds to your application’s access request by using the redirect_uri specified in the request. If the user approves the access request, then the response contains an authorization code as shown here:


1
2
https://www.mydemoapp.com/oauth-redirect?state=security_token%3D138r5719ru3e1%26url
%3Dhttps://www.mydemoapp.com/oauth-redirect&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&realmId=1231434565226279
URL parameter Description
code Authorization code returned by the server, to be used in the next step
state Confirm that the state received from Intuit matches the state token you sent in the authentication request. This round-trip verification helps to ensure that the user, not a malicious script, is making the request.

If the user does not approve the request, the response contains an error message. The authorization code or error message that is returned to the web server appears on the query string, as shown below:


Error Response Description
access_denied The user did not authorize the request.
invalid_scope An invalid scope string was sent in the request.

Note

Note

If your response endpoint renders an HTML page, any resources on that page will be able to see the authorization code in the URL. Scripts can read the URL directly, and all resources may be sent the URL in the Referer HTTP header. Carefully consider if you want to send authorization credentials to all resources on that page (especially third-party scripts such as social plugins and analytics). To avoid this issue, we recommend that the server first handle the request, then redirect to another URL that doesn’t include the response parameters.

Step 5: Exchange authorization code to obtain Id token and access token

After the app receives the authorization code, it exchanges the authorization code for an access token and ID token.


.NET

Java

PHP

Node.js

Python

1
2
3
4
5
6
7
// Get OAuth2 Bearer token and ID token
var tokenResponse = await auth2Client.GetBearerTokenAsync(code);

//retrieve access_token and refresh_token
tokenResponse.AccessToken
tokenResponse.RefreshToken
idToken = tokenResponse.IdentityToken;

1
2
3
4
5
6
7
8
9
//Prepare OAuth2PlatformClient
OAuth2PlatformClient client  = new OAuth2PlatformClient(oauth2Config);

//Get the bearer token (OAuth2 tokens)
BearerTokenResponse bearerTokenResponse = client.retrieveBearerTokens(authCode, redirectUri);

//retrieve the token using the variables below
bearerTokenResponse.getAccessToken()
bearerTokenResponse.getIdToken()

1
2
3
$accessTokenObj = $OAuth2LoginHelper->exchangeAuthorizationCodeForToken("authorizationCode", "RealmID");
$accessTokenValue = $accessTokenObj->getAccessToken();
$refreshTokenValue = $accessTokenObj->getRefreshToken();

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Parse the redirect URL for authCode and exchange them for tokens
var parseRedirect = req.url;

// Exchange the auth code retrieved from the **req.url** on the redirectUri
oauthClient.createToken(parseRedirect)
    .then(function(authResponse) {
        console.log('The Token is  '+ JSON.stringify(authResponse.getJson()));
    })
    .catch(function(e) {
        console.error("The error message is :"+e.originalMessage);
        console.error(e.intuit_tid);
    });

1
2
3
4
5
6
7
// Get OAuth2 Bearer token
auth_client.get_bearer_token(auth_code, realm_id=realm_id)

//retrieve access_token and refresh_token
auth_client.access_token
auth_client.refresh_token
auth_client.id_token
HTTP/REST

Retrieve the base URI from the discovery document using the key, token_endpoint. The discussion here assumes the base URI (https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer) sends an HTTPS POST request to the URL above that includes the following parameters:


Field Description
code Required. The authorization code returned from the initial request.
redirect_uri Required. One of the redirect URIs listed for this project in the developer dashboard.
grant_type Required. As defined in the OAuth 2.0 specification, this field must contain a value of authorization_code.

The following snippet shows a sample request:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer HTTP/1.1
Accept: application/json
Authorization: Basic UTM0dVBvRDIwanp2OUdxNXE1dmlMemppcTlwM1d2
    NzRUdDNReGkwZVNTTDhFRWwxb0g6VEh0WEJlR3dheEtZSlVNaFhzeGxma1l
    XaFg3ZlFlRzFtN2szTFRwbw==
Content-Type: application/x-www-form-urlencoded
Host: oauth.platform.intuit.com
Body: grant_type=authorization_code&
code=L3114709614564VSU8JSEiPkXx1xhV8D9mv4xbv6sZJycibMUI&
redirect_uri=https://www.mydemoapp.com/oauth-redirect

Authorization header can be generated using the value below-

1
"Basic " + base64encode(client_id + ":" + client_secret)

The token server returns a JSON object that contains ID token in additional to access token. The following snippet shows a sample response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"token_type": "bearer",
"expires_in": 3600,
"refresh_token":"L311478109728uVoOkDSUCl4s8FDRvjHR6kUKz0RHe3WtZQuBq",
"x_refresh_token_expires_in":15552000,
"access_token":"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..KM1_Fezsm6BUSaqqfTedaA.
dBUCZWiVmjH8CdpXeh_pmaM3kJlJkLEqJlfmavwGQDThcf94fbj9nBZkjEPLvBcQznJnEmltCIvsTGX0ue_w45h7_
yn1zBoOb-1QIYVE0E5TI9z4tMUgQNeUkD1w-X8ECVraeOEecKaqSW32Oae0yfKhDFbwQZnptbPzIDaqiduiM_q
EFcbAzT-7-znVd09lE3BTpdMF9MYqWdI5wPqbP8okMI0l8aa-UVFDH9wtli80zhHb7GgI1eudqRQc0sS9zWWb
I-eRcIhjcIndNUowSFCrVcYG6_kIj3uRUmIV-KjJUeXdSV9kcTAWL9UGYoMnTPQemStBd2thevPUuvKrPdz3ED
ft-RVRLQYUJSJ1oA2Q213Uv4kFQJgNinYuG9co_qAE6A2YzVn6A8jCap6qGR6vWHFoLjM2TutVd6eOeYoL2bb7jl
QALEpYGj4E1h3y2xZITWvnmI0CEL_dYQX6B3QTO36TDaVl9WnTaCCgAcP6bt70rFlPYbCjOxLoI6qFm5pUwGLLp
67JZ36grc58k7NIyKJ8dLJUL_Q9r1WoUvw.ZS298t_u7dSlkfajxLfO9Q",
"id_token":"eyJraWQiOiJyNHA1U2JMMnFhRmVoRnpoajhnSSIsImFsZyI6IlJTMjU2In0.eyJzd
WIiOiJiMDUzZDk5NC0wN2Q1LTQ2OGQtYjdlZS0yMmUzNDlkMmU3MzkiLCJhdWQiOlsiTDM5ZWxTdWJGeGpQT1
NwZFpvWVdSS2lDQ0U2VElOanY2N1JvYUU4ekJxYkl4eGI0bEsiXSwicmVhbG1pZCI6IjExMDgwMzM0Nz
EiLCJhdXRoX3RpbWUiOjE0NjI1NTQ0NzUsImlzcyI6Imh0dHBzOlwvXC9vYXV0aC1lMmUucGxhdGZvcm
0uaW50dWl0LmNvbVwvb2F1dGgyXC92MVwvb3BcL3YxIiwiZXhwIjoxNDYyNTYxMzI4LCJpYXQiOjE0NjI1
NTc3Mjh9.BIJ9x_WPEOZsLJfQE3mGji_Q15j_rdlTyFYELiJM-W92fWSLC-TLEwCp5IrRhDWMvyvrLSMZCEd
QALYQpbVy8uKI22JgGWYvkwNEDweOjbYzyt33F4xtn3GGcW9nAwRtA3M19qquWyi7G0kcCZUDN8RfUXz2qKM
J6KPOfLVe2UQ"
}

Note

Note

Other fields may be included in the response, and your application should not treat this as an error.

The set shown above is the minimum set of fields that are present in the response:


Field Description
access_token The token that must be used to access the QuickBooks Online API.
refresh_token A token used when refreshing the access token.
x_refresh_token_expires_in The remaining lifetime, in seconds, for the connection, after which time the user must re-grant access.
expires_in The remaining lifetime of the access token in seconds. The value always returned is 3600 seconds (one hour). Use the refresh token to get a fresh one.
token_type Identifies the type of token returned. At this time, this field will always have the value Bearer.
id_token Returned for openid and associated user scopes for user authentication.
Step 6: Validate ID token

You need to validate all ID tokens on your server unless you know that they came directly from Intuit. Since most API libraries combine the validation with the work of decoding the base64 and parsing the JSON, you probably end up validating the token anyway as you access the fields in the ID token.


.NET

Java

PHP

Node.js

Python

1
var isTokenValid = await oauthClient.ValidateIDTokenAsync(tokenResponse.IdentityToken);

1
boolean valid = client.validateIDToken(bearerTokenResponse.getIdToken());

1
2
//PHP SDK sets id_token value only after validating it
//No additional step needed for validation

1
2
3
4
5
6
7
8
9
oauthClient.validateIdToken()
        .then(function(response){
            console.log('Is my ID token validated  : ' + response);
        })
        .catch(function(e) {
            console.log('The error is '+ JSON.stringify(e));
        });

        // Is my ID token validated : true

1
2
# Python client sets id_token value only after validating it
# No additional step needed for validation

Here are the validation steps to perform if you don’t use the client library :

  • The value of iss in the payload section is https://oauth.platform.intuit.com/op/v1.
  • The value of aud in the payload section matches your app’s client id, located on Keys tab of your app’s dashboard on developer.intuit.com. Keep in mind there are two versions, based on your development stage:
  • Development client ID—found on the Development Keys section, use only in the sandbox environment.
  • Production client ID—found on the Production Keys section, use only in the production environment.
  • The expiry time, in the exp field, in the payload sections has not passed.
  • The signature is properly signed by the issuer.
  • Scan through the array of keys at oauth.platform.intuit.com/op/v1/jwks for the public key information whose kid value matches that returned in the ID token header.
  • Use the exponent, e field, and modulo, m field, values to create the public key and to validate the signature.
JSON web token information

A JSON Web Token consists of three parts separated by dots:

  • Header
  • Payload
  • Signature

The header consists of two parts:

  • kid—the key id of the key used to sign the payload
  • alg—the hashing algorithm being used, such as HMAC SHA256 or RSA

Then, this JSON is Base64Url encoded to form the first part of the JWT. Here is an example:

1
2
3
4
{
    kid: "r4p5SbL2qaFehFzhj8gI",
    alg: "RS256"
}
Payload

The second part of the token is the payload, which contains the claims. Claims are metadata about the user. Intuit ID tokens contain the following fields:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "sub": "1182d6ec-2a1f-4aa3-af3f-bb3b95db45af",
  "aud": [
    "L3Y7SV6rRxVvArdYzlRxjPXo0b6ItrX4qFhopPXQ6aaEWgKyCa"
  ],
  "realmid": "123145880168382",
  "auth_time": 1464330769,
  "iss": "https://oauth.platform.intuit.com/op/v1",
  "exp": 1464335838,
  "iat": 1464332238
}
Claim Description
aud Identifies the audience that this ID token is intended for. It must be the OAuth 2.0 client ID of your application.
auth_time The time the ID token was authorized.
exp The time the ID token expires, represented in Unix time (integer seconds).
iat The time the ID token was issued, represented in Unix time (integer seconds).
iss The issuer identifier for the issuer of the response. This is always set to https://oauth.platform.intuit.com/op/v1.
realmid The ID that identifies the specific QuickBooks company to which a connection is made and is returned when either QuickBooks Online API or Payments API scopes are specified in the authorization request payload. You use this value in all QuickBooks API calls.
sub An identifier for the user, unique among all Intuit accounts and never reused. An Intuit account can have multiple emails at different points in time, but the sub value is never changed. Use sub within your application as the unique-identifier key for the user.
Signature

The signature is used to verify that the sender of the JWT is who it says it is and used to ensure that the message wasn’t changed along the way. To create the signature, sign a concatenation of the encoded header, the encoded payload, and a secret with the specified algorithm. For example, if you use the HMAC SHA256 algorithm, the signature is created in the following way:

1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Obtaining User Profile Information

To obtain additional profile information about the user, you can use the access token to retrieve data by calling the Intuit’s user profile endpoint.

The response to this endpoint depends on scopes requested during the initial access token request. Sample response:

1
2
3
4
5
6
7
{
   "sub": "1182d6ec-2a1f-4aa3-af3f-bb3b95db45af",
   "email": "john@doe.com",
   "emailVerified": true,
   "givenName": "John",
   "familyName": "Doe"
}

Sample code where scopes specified are openid, email, and profile:


.NET

Java

PHP

Node.js

Python

1
var userInfoResp = await auth2Client.GetUserInfoAsync(“accessToken‘);

1
2
3
4
5
//Prepare OAuth2PlatformClient
OAuth2PlatformClient client  = new OAuth2PlatformClient(oauth2Config);

//Get user info (Use access token from bearerTokenResponse)
UserInfoResponse response = client.getUserInfo(accessToken);

1
$userInfo = $OAuthLoginHelper::getUserInfo($accessToken);

1
2
3
4
5
6
7
oauthClient.getUserInfo()
        .then(function(response){
            console.log('The User Info is  : ' + JSON.stringify(response.json()));
        })
        .catch(function(e) {
            console.log('The error is '+ JSON.stringify(e));
        });

1
response = auth_client.get_user_info(access_token='EnterAccessTokenHere')
HTTP/REST

Retrieve the base URI from the discovery document using the key, userinfo_endpoint. The discussion here assumes the base URI (https://accounts.platform.intuit.com/v1/openid_connect/userinfo) sends an HTTPS GET request to the URL above:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
GET https://accounts.platform.intuit.com/v1/openid_connect/userinfo
Accept: application/json
Authorization: Bearer <access token>

{
   "sub": "1182d6ec-2a1f-4aa3-af3f-bb3b95db45af",
   "email": "john@doe.com",
   "emailVerified": true,
   "givenName": "John",
   "familyName": "Doe",
   "phoneNumber": "+1 6305555555",
   "phoneNumberVerified": false,
   "address": {
      "streetAddress": "2007 saint julien ct",
      "locality": "mountain view",
      "region": "CA",
      "postalCode": "94043",
      "country": "US"
   }
}

Note

Note

  • After obtaining user information, query your app’s user database. If the user already exists in your database but it’s Intuit identity has not be established before, initiate an application session for that user only after prompting the user to enter their password prior to linking the Intuit identity to their existing account.
  • If the user does not exist in your user database, redirect the user to your new-user, sign-up flow. You may be able to auto-register the user based on the information you receive from intuit, or at the very least you may be able to pre-populate many of the fields that you require on your registration form.
Discovery document

The OpenID Connect protocol requires the use of multiple URLs for authenticating users, and for requesting resources including tokens, user information, and public keys.


To simplify the implementation and increase flexibility, OpenID Connect allows the use of a discovery document, a JSON document found at a well known location containing key-value pairs that provide details about the OpenID Connect configuration, including the URLs of the authorization, token, userinfo, and public-keys URLs. The discovery document for Intuit’s OpenID Connect service is located here:

Sandbox: https://developer.api.intuit.com/.well-known/openid_sandbox_configuration

Production: https://developer.api.intuit.com/.well-known/openid_configuration


.NET

Java

PHP

Node.js

Python

1
2
3
// .Net OAuth2 Client gets the Discovery document as part of OAuth2Client object
public static OAuth2Client auth2Client = new OAuth2Client(“clientid”, “clientsecret”, “redirectUrl”, “environment”);
DiscoveryResponse discoveryDoc = auth2Client.DiscoveryDoc;

1
2
//change environment enum to PRODUCTION to access Discovery document in production environment
DiscoveryAPIResponse discoveryAPIResponse = new DiscoveryAPIClient().callDiscoveryAPI(Environment.SANDBOX);

1
// PHP SDK store the discorveryDoc in the constants. No need to get it.

1
// Node.js client library stores URLs, no additional calls needed.

1
// Python client gets discovery documents as part of the constructor, no additional calls needed
HTTP/REST

To call the discovery document, make a HTTPS GET request to the discovery document endpoint.

The following snippet shows a sample request:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
GET https://developer.api.intuit.com/.well-known/openid_configuration HTTP/1.1
Accept: application/json

{
   issuer:"https://oauth.platform.intuit.com/op/v1",
   authorization_endpoint:"https://appcenter.intuit.com/connect/oauth2",
   token_endpoint:"https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
   userinfo_endpoint:"https://accounts.intuit.com/v1/openid_connect/userinfo",
   revocation_endpoint:"https://developer.API.intuit.com/v2/oauth2/tokens/revoke",
   jwks_uri:"https://oauth.platform.intuit.com/op/v1/jwks",
   response_types_supported:[
      "code"
   ],
   subject_types_supported:[
      "public"
   ],
   id_token_signing_alg_values_supported:[
      "RS256"
   ],
   scopes_supported:[
      "openid",
      "email",
      "profile",
      "address",
      "phone"
   ],
   token_endpoint_auth_methods_supported:[
      "client_secret_post",
      "client_secret_basic"
   ],
   claims_supported:[
      "aud",
      "exp",
      "iat",
      "iss",
      "realmid",
      "sub"
   ]
}
Refresh the token

Access tokens periodically expire. You can refresh an access token without prompting the user for permission.


.NET

Java

PHP

Node.js

Python

1
2
3
4
5
// Instantiate object
public static OAuth2Client oauthClient = new OAuth2Client(“clientid”, “clientsecret”, “redirectUrl”, “environment”); // environment is “sandbox” or “production”

//Refresh token endpoint
var tokenResp = await oauthClient.RefreshTokenAsync(“refreshToken”);

1
2
3
4
5
6
7
8
//Prepare the config
OAuth2Config oauth2Config = new OAuth2Config.OAuth2ConfigBuilder("OAuth2AppClientId", "OAuth2AppClientSecret").callDiscoveryAPI(Environment.SANDBOX).buildConfig();

//Prepare OAuth2PlatformClient
OAuth2PlatformClient client  = new OAuth2PlatformClient(oauth2Config);

//Call refresh endpoint
BearerTokenResponse bearerTokenResponse = client.refreshToken("refreshToken"); //set refresh token

1
2
3
4
5
$oauth2LoginHelper = new OAuth2LoginHelper($ClientID,$ClientSecret);
$accessTokenObj = $oauth2LoginHelper->
                    refreshAccessTokenWithRefreshToken($theRefreshTokenValue);
$accessTokenValue = $accessTokenObj->getAccessToken();
$refreshTokenValue = $accessTokenObj->getRefreshToken();

1
2
3
4
5
6
7
8
   oauthClient.refresh()
        .then(function(authResponse) {
            console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json()));
        })
        .catch(function(e) {
            console.error("The error message is :"+e.originalMessage);
            console.error(e.intuit_tid);
        });

1
2
3
4
5
6
7
8
9
//Instantiate client
auth_client = AuthClient(
    “client_id”,
    “client_secret”,
    “redirect_uri”,
    “Environment”, # “sandbox” or “production”
)
// Refresh token endpoint
auth_client.refresh(refresh_token=”refresh_token”)
HTTP/REST

To refresh an access token, your application sends an HTTPS POST request to Intuit’s authorization server (https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer) that includes the following parameters:


Field Description
grant_type As defined in the OAuth 2.0 specification, this field must contain a value of refresh_token
refresh_token The refresh token returned from the authorization code exchange

The following snippet shows a sample request:

1
2
3
4
5
6
7
8
POST /oauth2/v1/tokens/bearer HTTP/1.1
Accept: application/json
Authorization: Basic UTM0dVBvRDIwanp2OUdxNXE1dmlMemppcTlwM1d2
    NzRUdDNReGkwZVNTTDhFRWwxb0g6VEh0WEJlR3dheEtZSlVNaFhzeGxma1l
    XaFg3ZlFlRzFtN2szTFRwbw==
Content-Type: application/x-www-form-urlencoded
Body: grant_type=refresh_token&
refresh_token=Q311488394272qbajGfLBwGmVsbF6VoNpUKaIO5oL49aXLVJUB

Authorization header can be generated using the value below-

1
"Basic " + base64encode(client_id + ":" + client_secret)

As long as the user has not revoked the access granted to the application, the token server returns a JSON object that contains a new access token. The following snippet shows a sample response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
"token_type": "bearer",
"expires_in": 3600,
"refresh_token":"Q311488394272qbajGfLBwGmVsbF6VoNpUKaIO5oL49aXLVJUB",
"x_refresh_token_expires_in":15551893,
"access_token":"eJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGGlyIn0..KM1_Fezsm6BUSaqqfTedaA.
dBUCZWiVmjH8CdpXeh_pmaM3kJlJkLEqJlfmavwGQDThcf94fbj9nBZkjEPLvBcQznJnEmltCIvsTGX0ue_w45h7_
yn1zBoOb-1QIYVE0E5TI9z4tMUgQNeUkD1w-X8ECVraeOEecKaqSW32Oae0yfKhDFbwQZnptbPzIDaqiduiM_q
EFcbAzT-7-znVd09lE3BTpdMF9MYqWdI5wPqbP8okMI0l8aa-UVFDH9wtli80zhHb7GgI1eudqRQc0sS9zWWb
I-eRcIhjcIndNUowSFCrVcYG6_kIj3uRUmIV-KjJUeXdSV9kcTAWL9UGYoMnTPQemStBd2thevPUuvKrPdz3ED
ft-RVRLQYUJSJ1oA2Q213Uv4kFQJgNinYuG9co_qAE6A2YzVn6A8jCap6qGR6vWHFoLjM2TutVd6eOeYoL2bb7jl
QALEpYGj4E1h3y2xZITWvnmI0CEL_dYQX6B3QTO36TDaVl9WnTaCCgAcP6bt70rFlPYbCjOxLoI6qFm5pUwGLLp
67JZ36grc58k7NIyKJ8dLJUL_Q9r1WoUvw.ZS298t_u7dSlkfajxLfO9Q"
}
Revoke token/Disconnect

Your app can programmatically revoke access given to it by a specific user when they click the Disconnect link in your app. Use the revoke endpoint to request permissions granted to the application to be removed.


.NET

Java

PHP

Node.js

Python

1
2
3
4
5
// Instantiate object
public static OAuth2Client oauthClient = new OAuth2Client(“clientid”, “clientsecret”, “redirectUrl”, “environment”); // environment is “sandbox” or “production”

//Revoke token endpoint
var tokenResp = await oauthClient.RevokeTokenAsync(“refreshToken");

1
2
3
4
5
6
7
8
//Prepare the config
OAuth2Config oauth2Config = new OAuth2Config.OAuth2ConfigBuilder("OAuth2AppClientId", "OAuth2AppClientSecret").callDiscoveryAPI(Environment.SANDBOX).buildConfig();

//Prepare OAuth2PlatformClient
OAuth2PlatformClient client  = new OAuth2PlatformClient(oauth2Config);

//Call revoke endpoint
PlatformResponse response  = client.revokeToken("refreshToken"); //set refresh token

1
2
$oauth2LoginHelper = new OAuth2LoginHelper($clientID,$clientSecret);
$revokeResult = $oauth2LoginHelper->revokeToken($yourToken);

1
2
3
4
5
6
7
8
oauthClient.revoke(params)
        .then(function(authResponse) {
            console.log('Tokens revoked : ' + JSON.stringify(authResponse.json()));
        })
        .catch(function(e) {
            console.error("The error message is :"+e.originalMessage);
            console.error(e.intuit_tid);
        });

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//Instantiate client
auth_client = AuthClient(
    “client_id”,
    “client_secret”,
    “redirect_uri”,
    “Environment”, # “sandbox” or “production”
)

// Refresh token endpoint
auth_client.revoke(token=”refresh_token”)
HTTP/REST

To revoke an token, your application sends an HTTPS POST request to revoke endpoint (https://developer.api.intuit.com/v2/oauth2/tokens/revoke) and includes the token as a parameter

The following snippet shows a sample request:

1
2
3
4
5
6
7
8
9
POST https://developer.api.intuit.com/v2/oauth2/tokens/revoke HTTP/1.1
Accept: application/json
Authorization: Basic UTM0dVBvRDIwanp2OUdxNXE1dmlMemppcTlwM1d2
    NzRUdDNReGkwZVNTTDhFRWwxb0g6VEh0WEJlR3dheEtZSlVNaFhzeGxma1l
    XaFg3ZlFlRzFtN2szTFRwbw==
Content-Type: application/json
{
 "token": "{bearerToken or refreshToken}"
}

Authorization header can be generated using the value below:

1
"Basic " + base64encode(client_id + ":" + client_secret)

If the revocation is successfully processed, then the status code of the response is 200. For error conditions, a status code 400 is returned along with an error code.

Sample Code
Language Client Library Sample
GoLang No Yes
Ruby No Yes
.Net Yes

Yes

MVC5

Without library

Java Yes

Using client library

Without library

PHP Yes

Using client library

Without library

Node.js Yes

Using client library

Using 3rd Party Library

Without library

Python Yes

Using client library

Without library

Sign in with Intuit button


qbo/docs/develop/authentication-and-authorization/SIWI_openid.png

Add a Sign in with Intuit button button for your users to connect your application to their QuickBooks Online Company via the OAuth Authorization flow.