PureBasic
PureBasic
QuickBooks - Automatically Refresh Access Token with No User Interaction
See more QuickBooks Examples
Demonstrates how to automaticaly refresh an expired access token and retry the request after a 401 authorization error.Chilkat PureBasic Downloads
IncludeFile "CkJsonObject.pb"
IncludeFile "CkDateTime.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkOAuth2.pb"
IncludeFile "CkRest.pb"
IncludeFile "CkDtObj.pb"
Procedure ChilkatExample()
success.i = 0
; This example assumes the Chilkat API to have been previously unlocked.
; See Global Unlock Sample for sample code.
; Get our previously obtained OAuth2 access token, which should contain JSON like this:
; {
; "expires_in": 3600,
; "x_refresh_token_expires_in": 8726400,
; "refresh_token": "L011546037639r ... 3vR2DrbOmg0Sdagw",
; "access_token": "eyJlbmMiOiJBMTI4Q0 ... oETJEMbeggg",
; "token_type": "bearer"
; }
jsonToken.i = CkJsonObject::ckCreate()
If jsonToken.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkJsonObject::ckLoadFile(jsonToken,"qa_data/tokens/qb-access-token.json")
rest.i = CkRest::ckCreate()
If rest.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
; Connect using TLS.
; A single REST object, once connected, can be used for many Quickbooks REST API calls.
; The auto-reconnect indicates that if the already-established HTTPS connection is closed,
; then it will be automatically re-established as needed.
bAutoReconnect.i = 1
success = CkRest::ckConnect(rest,"sandbox-quickbooks.api.intuit.com",443,1,bAutoReconnect)
If success = 0
Debug CkRest::ckLastErrorText(rest)
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
ProcedureReturn
EndIf
sbAuth.i = CkStringBuilder::ckCreate()
If sbAuth.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkStringBuilder::ckAppend(sbAuth,"Bearer ")
CkStringBuilder::ckAppend(sbAuth,CkJsonObject::ckStringOf(jsonToken,"access_token"))
CkRest::setCkAuthorization(rest, CkStringBuilder::ckGetAsString(sbAuth))
CkRest::ckAddHeader(rest,"Accept","application/json")
CkRest::setCkAllowHeaderFolding(rest, 0)
; The company ID is 123146096291789
; The employee ID is 58
responseBody.s = CkRest::ckFullRequestNoBody(rest,"GET","/v3/company/123146096291789/employee/58?minorversion=45")
If CkRest::ckLastMethodSuccess(rest) = 0
Debug CkRest::ckLastErrorText(rest)
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
CkStringBuilder::ckDispose(sbAuth)
ProcedureReturn
EndIf
; If we get a 401 authorization error, then it's likely because the access token expired.
; We can automatically refresh it without interaction from the user.
If CkRest::ckResponseStatusCode(rest) = 401
oauth2.i = CkOAuth2::ckCreate()
If oauth2.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkOAuth2::setCkTokenEndpoint(oauth2, "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer")
; Replace these with actual values.
CkOAuth2::setCkClientId(oauth2, "QUICKBOOKS-CLIENT-ID")
CkOAuth2::setCkClientSecret(oauth2, "QUICKBOOKS-CLIENT-SECRET")
; Get the "refresh_token"
CkOAuth2::setCkRefreshToken(oauth2, CkJsonObject::ckStringOf(jsonToken,"refresh_token"))
; Send the HTTP POST to refresh the access token..
success = CkOAuth2::ckRefreshAccessToken(oauth2)
If success = 0
Debug CkOAuth2::ckLastErrorText(oauth2)
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
CkStringBuilder::ckDispose(sbAuth)
CkOAuth2::ckDispose(oauth2)
ProcedureReturn
EndIf
Debug "New access token: " + CkOAuth2::ckAccessToken(oauth2)
; Update the JSON with the new tokens.
CkJsonObject::ckUpdateString(jsonToken,"access_token",CkOAuth2::ckAccessToken(oauth2))
; Save the new JSON access token response to a file.
; The access + refresh tokens contained in this JSON will be needed for the next refresh.
sbJson.i = CkStringBuilder::ckCreate()
If sbJson.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkJsonObject::setCkEmitCompact(jsonToken, 0)
CkJsonObject::ckEmitSb(jsonToken,sbJson)
CkStringBuilder::ckWriteFile(sbJson,"qa_data/tokens/qb-access-token.json","utf-8",0)
Debug "OAuth2 token refreshed!"
Debug "New Access Token = " + CkOAuth2::ckAccessToken(oauth2)
CkStringBuilder::ckClear(sbAuth)
CkStringBuilder::ckAppend(sbAuth,"Bearer ")
CkStringBuilder::ckAppend(sbAuth,CkOAuth2::ckAccessToken(oauth2))
CkRest::setCkAuthorization(rest, CkStringBuilder::ckGetAsString(sbAuth))
; Now retry the request with the refreshed access token...
responseBody = CkRest::ckFullRequestNoBody(rest,"GET","/v3/company/123146096291789/employee/58?minorversion=45")
If CkRest::ckLastMethodSuccess(rest) = 0
Debug CkRest::ckLastErrorText(rest)
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
CkStringBuilder::ckDispose(sbAuth)
CkOAuth2::ckDispose(oauth2)
CkStringBuilder::ckDispose(sbJson)
ProcedureReturn
EndIf
EndIf
; We should expect a 200 response if successful.
If CkRest::ckResponseStatusCode(rest) <> 200
Debug "Request Header: "
Debug CkRest::ckLastRequestHeader(rest)
Debug "----"
Debug "Response StatusCode = " + Str(CkRest::ckResponseStatusCode(rest))
Debug "Response StatusLine: " + CkRest::ckResponseStatusText(rest)
Debug "Response Header:"
Debug CkRest::ckResponseHeader(rest)
Debug responseBody
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
CkStringBuilder::ckDispose(sbAuth)
CkOAuth2::ckDispose(oauth2)
CkStringBuilder::ckDispose(sbJson)
ProcedureReturn
EndIf
; Load the JSON response into a JSON object for parsing.
; A sample JSON response is shown below.
json.i = CkJsonObject::ckCreate()
If json.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkJsonObject::ckLoad(json,responseBody)
; These will be used for parsing date/time strings..
dtime.i = CkDateTime::ckCreate()
If dtime.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
bLocalTime.i = 1
; Show the JSON.
CkJsonObject::setCkEmitCompact(json, 0)
Debug CkJsonObject::ckEmit(json)
; Get some information from the JSON..
Debug "Name: " + CkJsonObject::ckStringOf(json,"Employee.DisplayName")
Debug "Id: " + CkJsonObject::ckStringOf(json,"Employee.Id")
Debug "City: " + CkJsonObject::ckStringOf(json,"Employee.PrimaryAddr.City")
Debug "PostalCode: " + CkJsonObject::ckStringOf(json,"Employee.PrimaryAddr.PostalCode")
; Load the CreateTime into a CkDateTime...
CkDateTime::ckSetFromTimestamp(dtime,CkJsonObject::ckStringOf(json,"Employee.MetaData.CreateTime"))
dt.i = CkDtObj::ckCreate()
If dt.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkDateTime::ckToDtObj(dtime,bLocalTime,dt)
Debug Str(CkDtObj::ckMonth(dt)) + "/" + Str(CkDtObj::ckDay(dt)) + "/" + Str(CkDtObj::ckYear(dt)) + " " + Str(CkDtObj::ckHour(dt)) + ":" + Str(CkDtObj::ckMinute(dt))
Debug "Success."
; Use this online tool to generate parsing code from sample JSON:
; Generate Parsing Code from JSON
; ------------------------------------------------------
; The JSON response looks like this:
; {
; "Employee": {
; "SSN": "XXX-XX-XXXX",
; "PrimaryAddr": {
; "Id": "116",
; "Line1": "45 N. Elm Street",
; "City": "Middlefield",
; "CountrySubDivisionCode": "CA",
; "PostalCode": "93242"
; },
; "BillableTime": false,
; "domain": "QBO",
; "sparse": false,
; "Id": "98",
; "SyncToken": "0",
; "MetaData": {
; "CreateTime": "2015-07-24T09:34:35-07:00",
; "LastUpdatedTime": "2015-07-24T09:34:35-07:00"
; },
; "GivenName": "Bill",
; "FamilyName": "Miller",
; "DisplayName": "Bill Miller",
; "PrintOnCheckName": "Bill Miller",
; "Active": true,
; "PrimaryPhone": {
; "FreeFormNumber": "234-525-1234"
; }
; },
; "time": "2015-07-24T09:35:54.805-07:00"
;
CkJsonObject::ckDispose(jsonToken)
CkRest::ckDispose(rest)
CkStringBuilder::ckDispose(sbAuth)
CkOAuth2::ckDispose(oauth2)
CkStringBuilder::ckDispose(sbJson)
CkJsonObject::ckDispose(json)
CkDateTime::ckDispose(dtime)
CkDtObj::ckDispose(dt)
ProcedureReturn
EndProcedure