Home Company Business Solutions Consulting Contact Us
Pharmaceutical chargeback processing
Home Site MapaConsultingaKB10004

Quickbooks OAuth 2.0 authentication in Windows Forms .Net Appliations

Prepared by Dr. Alexander Werner. KB# 10005.

This case study relied upon the Pharma Suite chargeback processing module, developed by Relasoft Solutions Inc for pharmaceutical manufacturers using Quickbooks.

1. Introduction

When I started updating my Windows Forms applications integrating with Quickbooks to support OAuth 2.0, I found many examples for web applications, yet none for Visual Basic or C# Windows Forms apps, using SDK. I opened a support case: https://help.developer.intuit.com/s/feed/0D50f00006GyPKN, and found out that Intuit "support only server side Oauth2 model".

The good news is that OAuth 2.0 works find in Windows Forms apps!

However, it was not easy to discover all required steps and experiment with different classes and methods to figure out how to do it.

 

 Below I list the steps that needs to be done to migrate from OAuth 1.0 to OAuth 2.0.

2. Preparing the Environment

1. Download a latest version of Postman application from https://www.getpostman.com/downloads. The right version of Postman will have an option OAuth 2.0 under Type values for Authorization requests, and will generate new types of tokens.

Click on Get New Access Token to get values for Access Token and Refresh Token, which are required for Windows Forms app authentication. Copy them somewhere because they will be used.

2. In the Windows Forms application, upgrade IPP library to IppDotNetSdkForQuickBooksApiV3. NuGet the package, install it, and make sure that class Intuit.Ipp.OAuth2PlatformClient.OAuth2Client(...) is available.  The class represents a connection to Quickbooks, and has methods to receive various tokens.

In Windows Forms application, the Access Token generated in Postman stays unchanged for its life duration of 100 days, after which it needs to be refreshed in Postman. The Refresh Token needs to be updated more frequently: documentation tells that the life span of this token is one hour, but there is no reason not to request its update before each call to the database.

In Windows Forms apps the Access token lives long, and Refresh token is updated all the time. In Web apps is seems to work the other way.

There is no way to obtain a new value of Access Token back to the Windows Forms application. Calling method GetBearerTokenAsync, recommended for Web applications, just moves all tokens out of sync and requires generating new tokens in Postman.

3. Configuring Production

Redirect URL have to be setup for Production in the Playground as following:

URI 1: https://www.getpostman.com/oauth2/callback

URI 2: https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl

In Postman, obtain Access and Refresh tokens for each company the application will be accessing.

Reset Base URL to https://quickbooks.api.intuit.com

4. Refresh and Access Tokens

Both Access and Refresh tokens are first generated in Postman. The Access Token is supposed to remain valid for an hour.

Documentation says that the Refresh token is valid for 100 days. I believe it is valid for 100 days if it's not used. However, if your program used Refresh token to receive an updated Access token, the value of the Refresh token may also change. It does not change every time the tokens are refreshed, with Refresh token seem to be valid for somewhere from one to seven days. 

So, once the function to retrieve updated Access token is called, both Access and Refresh token values should be stored somewhere. 

I found is helpful to check if Access token is still valid before calling the token update code. And now I keep ServiceContext object open for executing multiple queries, rather than re-creating everything for each query.

 

5. Example of Visual Basic Code to Retrieve Invoice List

The example below opens a connection to Quickbooks, updated Refresh token, executes a query and accepts the query result.

 Start with defining four string variables. ClientID and ClientSecret are defined on the environment level. Redirect URL is set to the same value for all applications. AppEnvironment differentiates between sandbox and producton.

 

Dim lcClientID As String =  ".."

 Dim lcClientSecret As String = ".."

 Dim lcReDirectURL As String = "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl"

Dim lcAppEnvironment As String = "Sandbox"   ' Another possible value is "Production"

' Start with opening oAuthClient

Dim oAuthClient As Intuit.Ipp.OAuth2PlatformClient.OAuth2Client

oAuthClient = New Intuit.Ipp.OAuth2PlatformClient.OAuth2Client(lcClientID, lcClientSecret, lcReDirectURL, lcAppEnvironment)

Dim lcRefreshToken, lcAccessToken, lcAccessTokenSecret, lcConsumerKey, lcConsumerSecret As String

 ' Set the SecurityProtocol to Tls12:

 System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12

 

 ' Plug in the values generated in Postman into Refresh and Access tokens:

 lcRefreshToken = ".."

 lcAccessToken = ".."

 ' Check if Access token is still valid here. If the Access token is not valid anymore, both tokens have to be updated before the call to the database:

 Dim loTokenResponseTask As Task(Of Intuit.Ipp.OAuth2PlatformClient.TokenResponse) = oauthClient.RefreshTokenAsync(lcRefreshToken)

 Dim loTokenResponseContent As Intuit.Ipp.OAuth2PlatformClient.TokenResponse = Await loTokenResponseTask

 lcAccessToken = loTokenResponseContent.AccessToken

 lcRefreshToken = loTokenResponseContent.RefreshToken

 

 Dim oauthValidator As Intuit.Ipp.Security.OAuth2RequestValidator

 oauthValidator = New Intuit.Ipp.Security.OAuth2RequestValidator(lcAccessToken)

' Get your RealmID

 Dim realmId As String = "..."

 Dim serviceContext As Intuit.Ipp.Core.ServiceContext = New Intuit.Ipp.Core.ServiceContext(realmId, Intuit.Ipp.Core.IntuitServicesType.QBO, oauthValidator)

 

' Let's enable logging here:

 serviceContext.IppConfiguration.Logger.RequestLog.EnableRequestResponseLogging = True

 serviceContext.IppConfiguration.Logger.RequestLog.ServiceRequestLoggingLocation = "D:\ServiceContextFromLogs\"

 

 ' Common setting for both ServiceContexts:

 serviceContext.IppConfiguration.MinorVersion.Qbo = “23”

 serviceContext.IppConfiguration.BaseUrl.Qbo = "https://sandbox-quickbooks.api.intuit.com/"

  ' Serialization Format Json or xml

 serviceContext.IppConfiguration.Message.Request.SerializationFormat = Intuit.Ipp.Core.Configuration.SerializationFormat.Json

 serviceContext.IppConfiguration.Message.Response.SerializationFormat = Intuit.Ipp.Core.Configuration.SerializationFormat.Json

 

' Compression Format can be GZip or Deflate:

 serviceContext.IppConfiguration.Message.Request.CompressionFormat = Intuit.Ipp.Core.Configuration.CompressionFormat.GZip

 serviceContext.IppConfiguration.Message.Response.CompressionFormat = Intuit.Ipp.Core.Configuration.CompressionFormat.GZip

 ' Retry 5 times at an interval of 1 Second if service fails. Note that RetryPolicy moved from Intuit.Ipp.Retry to Intuit.Ipp.Core.

Dim retryInterval As TimeSpan = New TimeSpan(0, 0, 0, 1)

serviceContext.IppConfiguration.RetryPolicy = New Intuit.Ipp.Core.IntuitRetryPolicy(5, retryInterval)

 ' For data updates, create DataService:

 Dim loDataService As Intuit.Ipp.DataService.DataService

 loDataService = New Intuit.Ipp.DataService.DataService(serviceContext)

 

 ' Find invoice by its number

 Dim loListOfInvoices As System.Collections.ObjectModel.ReadOnlyCollection(Of Intuit.Ipp.Data.Invoice)

 Dim InvoiceQueryService As Intuit.Ipp.QueryFilter.QueryService(Of Intuit.Ipp.Data.Invoice) = New Intuit.Ipp.QueryFilter.QueryService(Of Intuit.Ipp.Data.Invoice)(serviceContext)

 

Dim lcQueryFrom As String

 lcQueryFrom = "Select * from Invoice "

 Try

    loListOfInvoices = InvoiceQueryService.ExecuteIdsQuery(lcQueryFrom, Intuit.Ipp.QueryFilter.QueryOperationType.query)

      Catch ex As Intuit.Ipp.Exception.CommunicationException

         MsgBox("Intuit.Ipp.Exception.CommunicationException")

      Catch ex As Intuit.Ipp.Exception.IdsException

         MsgBox("IdsException1:" + ex.InnerException.Message)

     Catch ex As Exception

         MsgBox("Exception " + ex.Message)

 End Try

 Dim loInvoiceFrom As Intuit.Ipp.Data.Invoice

Dim lnInoiceNo As Integer

 lnInoiceNo = 1

 loInvoiceFrom = loListOfInvoices(lnInoiceNo)

 Debug.Write(loInvoiceFrom.DocNumber)

The type were specified in full, rather than defining Import statements, to explicitly show the required libraries.

The code to close services and to release other variables is the same as in OAuth 1.0.

 

Once serviceContext object is established, the rest of the coding is the same between OAuth 1.0 and OAuth 2.0.

6. Conclusion

 

Postman application and .Net library need to be updated to the version supporting OAuth 2.0. Quickbooks authentication OAuth 2.0 in Windows Forms application is based on a fixed value of Access token, generated in the Postman application. Refresh token is updated from time to time when Access token is refreshed. As long, as the Access tokens is valid, it can be used to access the database multiple times. Variables RedirectURL, AppEnvironment, SecurityProtocol and IPPConfiguration have to be set to specific values. The rest of coding is the same.

 

 

Alexander Werner, Ph.D, is a founding partner and the chief software architect for Relasoft Solutions Inc, the company specializing in software for Healthcare Management industry. Relasoft main product Pharma Suite includes modules to process several typical tasks in the pharmaceutical environment: Chargebacks, Rebates, Medicaid MDRP, Medicare Part D Coverage Gap Discount program, Gross-To-Net Profitability Analysis and numerous modules to interact with various ERP.

Here are the links for more info on Pharma Suite and to contact Alexander.

 

© Relasoft Solutions Inc. All Rights Reserved.