Migration from OAuth 1.0 to OAuth 2.0

Use this information to migrate your apps from OAuth 1.0 to OAuth 2.0 and from OpenID 2.0 to OpenID Connect (for apps implementing Intuit single sign-on). During the migration process, your OAuth 1.0 apps remain available for connections until you switch to OAuth 2.0.


The migration process involves the following steps:

  • Step 1: Implement OAuth 2.0 and OpenID Connect
  • Step 2: Switch to OAuth 2.0 and OpenID Connect
  • Step 3: Migrate your current OAuth 1.0 access tokens to OAuth 2.0 tokens

Note

Note

You must migrate your app to OAuth 2.0/OpenID Connect by December 17, 2019 after which all existing OAuth 1.0 access tokens will be revoked and no new OAuth 1.0 connections will be allowed. In addition, OpenID 2.0 will no longer be available, and OpenID 2.0 requests will fail.

Step 1: Implement OAuth 2.0 and OpenID Connect

Begin your migration by implementing OAuth 2.0 and OpenID connect as described in the workflow links in this step. Make sure your OAuth 1.0 implementation remains available during migration in case you need to switch back to it.

While implementing this workflow for migration, note that:

  • A user’s OpenID 2.0 openid.claimed_id will transfer to the equivalent OpenID Connect unique identifier claim, known as sub. This provides a seamless migration between OpenID 2.0 and OpenID Connect.

Example below shows how the OpenID 2.0 openid.claimed_id gets converted to OpenID Connect sub.


OpenID 2.0 openid.claimed_id:https://openid.intuit.com/Identity-c7760cb7-7cff-4a98-a47d-707c96eba8b7


OpenID Connect sub: c7760cb7-7cff-4a98-a47d-707c96eba8b7

  • In the OpenID Connect authorization request, include this scope string: openid intuit_name email. This exempts authorized users from being asked for consent again. If you include profile in the scope, users will be asked to consent again.
Step 2: Switch to OAuth 2.0 and OpenID Connect

Once your OAuth 2.0 and OpenID Connect workflows are implemented, you can start accepting new connections with them. Your existing OAuth 1.0 access tokens and connections will remain valid until after you migrate them in Step 3.


For apps not on the app store, you’re set. Switch to your OAuth 2.0 implementation via your code; no further action required on the developer portal.


For apps using Intuit single sign-on on the QuickBooks app store, perform the following steps:


Launch URL: Make sure that a user can use OpenID Connect to do single sign-on at the Launch URL that you specified in the App Settings.
Disconnect URL: Make sure that when the user disconnects your app from their QuickBooks Online company and lands on the Disconnect URL that you provided in the App Settings, the Disconnect URL is ready for users to use single sign-on with OpenID Connect. Your app should also appropriately invalidate either the OAuth 1.0a access token or OAuth 2.0 refresh token, depending on the user’s authentication mechanism.
  • Switch to OAuth 2.0/OpenID Connect by toggling the setting on your app’s Settings tab to OAuth 2.0. This lets you make sure that new connections from the QuickBooks App Store are using OAuth 2.0/OpenID Connect.

Note

Note

You can always toggle back to OAuth 1.0 if you experience any problems with your OAuth 2.0/ OpenID Connect implementation. The new OAuth 2.0 refresh tokens and old OAuth 1.0 access tokens will remain valid even if you toggle the settings.

qbo/docs/develop/authentication-and-authorization/intuit_sso.png
Step 3: Migrate your current OAuth 1.0 access tokens to OAuth 2.0 tokens

Use the Migration API to migrate an existing OAuth 1.0 access token to OAuth 2.0 without requiring consent from your currently connected users. You must do this once for each active connection to your app. If you app doesn’t have any active connections, this step can be skipped. See this API in action in the Migration tab in the OAuth 2.0 playground.


Prerequisites


Obtain Client Id/Secret: Make sure that a user can use OpenID Connect to do single sign-on at the Launch URL that you specified in the App Settings.
Define redirect URIs: Make sure that when the user disconnects your app from their QuickBooks Online company and lands on the Disconnect URL that you provided in the App Settings, the Disconnect URL is ready for users to use single sign-on with OpenID Connect. Your app should also appropriately invalidate either the OAuth 1.0a access token or OAuth 2.0 refresh token, depending on the user’s authentication mechanism.
Identify scopes: Make sure that when the user disconnects your app from their QuickBooks Online company and lands on the Disconnect URL that you provided in the App Settings, the Disconnect URL is ready for users to use single sign-on with OpenID Connect. Your app should also appropriately invalidate either the OAuth 1.0a access token or OAuth 2.0 refresh token, depending on the user’s authentication mechanism.

Note

Note

After an OAuth 1.0 token has been migrated, it remains valid for thirty days and then expires.

Migration API

Here are the endpoints for the migration API.

Making the request

Initiate the migration process for each connection by calling the Migration API.


.NET

Java

PHP

Node.js

Python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//OAuth1 validator
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(“accessToken”, ‘accessTokenSecret”, “consumerKey”, “consumerSecret”);

//Calling OAuth1 to OAuth2 migration helper
OAuth1ToOAuth2TokenMigrationHelper objMigrationHelper = new OAuth1ToOAuth2TokenMigrationHelper(EnvironmentForMigration.Sandbox);


List<OidcScopes> scopes = new List<OidcScopes>();
scopes.Add(OidcScopes.Accounting);
// convert scopes to string
String scopeVal = String.Join(" ", scopes.ToArray());
scopeVal = scopeValue.TrimEnd();

// Migrate tokens
MigratedTokenResponse oauth2Tokens = objMigrationHelper.GetOAuth2Tokens(scopeVal, “redirectUrl”, ‘clientId”, “clientSecret”, oauthValidator);

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//build oauth2config to get client id secret
OAuth2Config oAuth2Config = new OAuth2Config.OAuth2ConfigBuilder("clientId", "clientSecret").buildConfig();

//build migration request
OAuthMigrationRequest req = new OAuthMigrationRequest.OAuthMigrationRequestBuilder(Environment.SANDBOX, Scope.Accounting)
        .consumerKey("consumerKey")
        .consumerSecret("consumerSecret")
        .accessToken("accessToken")
        .accessSecret("accessTokenSecret")
        .oAuth2Config(oAuth2Config)
        .build();


// create migration service
OAuthMigrationClient oAuthMigrationService = new OAuthMigrationClient(req);
OAuthMigrationResponse result = oAuthMigrationService.migrate();

//retrieve the token using the variables below
result.getAccessToken()
result.getRefreshToken()

1
2
//Client ID and secret already stored in the login helper
$oauth2Token = $OAuth2LoginHelper->OAuth1ToOAuth2Migration($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret, $scope)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// Fill in the params object ( argument to the migrate function )

var params = {
    oauth_consumer_key : '<Enter oauth1ConsumerKey>',
    oauth_consumer_secret : '<Enter oauth1ConsumerSecret>',
    oauth_signature_method : 'HMAC-SHA1',
    oauth_timestamp : Math.round(new Date().getTime()/1000),
    oauth_nonce : 'nonce',
    oauth_version : '1.0',
    access_token : '<Enter OAuth1.0 access_token>',
    access_secret : '<Enter OAuth1.0 access_secret>',
    scope : [OAuthClient.scopes.Accounting]
}

oauthClient.migrate(params)
    .then(function(response){
        console.log('The response is '+ JSON.stringify(response));
    })
    .catch(function(e) {
        console.log('The error is '+e.message);
    });

 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
from intuitlib.client import AuthClient
from intuitlib.enums import Scopes
from intuitlib.migration import migrate

//Instantiate client
auth_client = AuthClient(
    “client_id”,
    “client_secret”,
    “redirect_uri”,
    “Environment”, # “sandbox” or “production”
)

// scopes
scopes = [
    Scopes.ACCOUNTING,
]

# Use the above client object to migrate tokens
migrate (
    “consumer_key”,
    “consumer_secret”,
    “access_key”,
    “access_secret”,
    auth_client,
    scopes,
)
HTTP/REST

Make an HTTPS POST request to the migration API URL.

The following snippet shows a sample request:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST https://developer.api.intuit.com/v2/oauth2/tokens/migrate HTTP/1.1
Accept: application/json
Authorization: OAuth oauth_consumer_key="<your_consumer_key>",oauth_token="<your_oauth_token>",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1549658993",oauth_nonce="qTRdaM",oauth_version="1.0",oauth_signature="<your_oauth_signature>"
Content-Type: application/json
Body: {
"scope":"<your_oauth_2_scopes>",
"redirect_uri":"<your_oauth_2_redirect_URI>",
"client_id":"<your_app_client_id>",
"client_secret":"<your_app_client_secret>"
}

The request body includes the following fields, all fields below are required for the API to work:

Field Description
scope

Required. Identifies the QuickBooks API access that your application is requesting. Identify scopes that correspond to the QuickBooks API access your application is requesting. These must match the data services your app currently requests. Refer to the APIs section of your app’s settings to determine what these are.


  • For QuickBooks Accounting use: com.intuit.quickbooks.accounting
  • For QuickBooks Payments use: com.intuit.quickbooks.payment
  • For both, use the string: com.intuit.quickbooks.accounting com.intuit.quickbooks.payment
redirect_uri Required. Determines where the response is sent. 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 http://localhost (no HTTPS with localhost).
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.
client_secret

Required. 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.
Handling the response

A successful response to this request contains the following fields:

Field Description
access_token OAuth 2.0 access token that must be used to access the QuickBooks API.
refresh_token Supply this 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.
realmId The QuickBooks company ID to which the app is connected. You use it in subsequent QuickBooks Online API endpoint URLs.

The response you receive is similar to this sample:

1
2
3
4
5
6
7
{
"access_token": "eyJlbmMiOiJBMTI....ZS298t_u7dSlkfajxLfO9Q",
"refresh_token": "L311478109728uVoOkDSUCl4s8FDRvjHR6kUKz0RHe3WtZQuBq", "x_refresh_token_expires_in": "15552000",
"expires_in": "3600",
"token_type": "bearer",
"realmId": "1231434565226279"
}
Error responses
Status Code Response payload
400
{
“error”:”invalid_client”, “error_description”:”Client not found: clientId=D8OP5fU3hXtBw9BeeTW10BlXaragBeBLuSCitiYCzDUH5PBqnass”

}

400
{
“error”:”invalid_redirect_uri”, “error_description”:”Client not found: clientId=D8OP5fU3hXtBw9BeeTW10BlXaragBeBLuSCitiYCzDUH5PBqnass”

}

500 Internal server error. Something went wrong while migrating this access_token.
Throttling

The Migration API has a throttling policy of five requests per second per application, after which an error is returned.

Client Libraries

These QuickBooks Online SDKs support the Migration API.

Note

Note

The version number above indicates the minimum version of the SDK that supports OAuth migration API. As a best practice always use the latest version of the SDK.

Sample Code


Samples apps are available here to help you with the migration.