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. |
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 ProductionRedirect 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 TokensBoth 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 ListThe 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" ' 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 = ".." 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
' 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)
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/" 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. 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)
lcQueryFrom = "Select * from Invoice " 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. |
|
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. |