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.
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 ”
loListOfInvoices = InvoiceQueryService.ExecuteIdsQuery(lcQueryFrom, Intuit.Ipp.QueryFilter.QueryOperationType.query)
Catch ex As Intuit.Ipp.Exception.CommunicationException
Catch ex As Intuit.Ipp.Exception.IdsException
MsgBox(“IdsException1:” + ex.InnerException.Message)
Catch ex As Exception
MsgBox(“Exception ” + ex.Message)
Dim loInvoiceFrom As Intuit.Ipp.Data.Invoice
Dim lnInoiceNo As Integer
lnInoiceNo = 1
loInvoiceFrom = loListOfInvoices(lnInoiceNo)
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.
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.