Quickbooks Online API OAUTH2 HTTPSecureSocket

Hello, Quickbooks online has a REST API. I’m a new when it comes to this and i am a little confused. Hopefully i get get some insight from someone here.

I’ve been able to authorize my app and i am at the point where i trade this code for an access token. Getting the authorization code used a GET method which was fine i just generated a url. Getting the access token is using the POST method though, and i am confused about how to set this up properly. Currently i’m trying to use an HTTPSecureSocket and sending a form but i am getting {“error”:“invalid_request”}.

The section of the API i’m in is here: QBO API Access Token

I’ve tried a couple different ways as you can probably tell i’m very confused.

[code] Dim form As Dictionary
Dim request As HTTPSecureSocket
request = New HTTPSecureSocket
request.Secure = True
'request.SetRequestContent(“application/json”,“Accept”)
'request.SetRequestContent(“Basic “+EncodeBase64(“Q0sBgx3XRaTtF26uaxoxrJ4FzWTcWayZ3BJvr7MiMirVu7MctO:pVSrR1T0cwhpJOO6IRer5rmgC2TtlMtkWTi7xQOj”),“Authorization”)
'request.SetRequestContent(“application/x-www-form-urlencoded”,“Content-Type”)
'request.SetRequestContent(“oauth.platform.intuit.com”,“Host”)
'request.SetRequestContent(“grant_type=authorization_code&code=”+app.qbo_AuthorizationCode+”&redirect_uri=https://myapp.com/cgi-bin/myapp.cgi/token”,“Body”)

dim url as string = “?”
url = url + “grant_type=authorization_code&”
url = url + “code=”+app.qbo_AuthorizationCode+"&"
url = url + “redirect_uri=https://myapp.com/cgi-bin/myapp.cgi/token”

// create and populate the form object
'form = New Dictionary
'form.Value(“code”) = app.qbo_AuthorizationCode
'form.Value(“redirect_uri”) = “https://myapp.com/cgi-bin/myapp.cgi/token
'form.Value(“grant_type”) = “authorization_code”

// setup the socket to POST the form
'request.SetFormData(form)
dim data as string = request.Post(qbo.token_endpoint+url,30)
Message(data)[/code]

Any help is appreciated. Thanks.

i have some code i use with soap is litter differences
https://blog.smartbear.com/apis/understanding-soap-and-rest-basics/

I’ve arrived at this code

[code] dim postData as new Dictionary
postData.Value(“code”) = app.qbo_AuthorizationCode
postData.Value(“redirect_uri”) = “https://myapp.cgi/token
postData.Value(“grant_type”) = “authorization_code”

dim request as new HTTPSecureSocket
request.Secure = True
request.ConnectionType = SSLSocket.TLSv12

request.SetFormData(postData)
Message(request.Post(qbo.token_endpoint,30))
[/code]
which has changed the error message. I may not have noticed it before but instead of getting this error message

{"error":"invalid_request"}

I am now getting this error message

{"error":"invalid_client"}

So i think i’m on the right track with the error switching from invalid_request to invalid_client. Anyone experienced with qbo api or have any insight to offer would be great. Thanks.

From the doc you linked:

[quote]client_id - The client ID you obtain from the developer dashboard.
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.[/quote]

Did you include your client_id in your request?

[quote=347410:@Tim Parnell]Did you include your client_id in your request?

[/quote]
I’m currently trying to figure out how it likes to be passed. It first wants me to calculate the Authorization Header as follows:


However when i do this and do SetRequestHeader it bring back the same invalid_client error.

[code] dim postData as new Dictionary
'postData.Value(“Authorization”) = “Basic " + EncodeBase64(qbo.ClientID+”:"+qbo.ClientSecret)
postData.Value(“code”) = app.qbo_AuthorizationCode
postData.Value(“redirect_uri”) = “https://myapp.cgi/token
postData.Value(“grant_type”) = “authorization_code”
dim request as new HTTPSecureSocket

request.Secure = True
request.ConnectionType = SSLSocket.TLSv12
request.SetRequestHeader(“Authorization”,“Basic " + EncodeBase64(qbo.ClientID+”:"+qbo.ClientSecret))
request.SetRequestHeader(“Content-Type”,“application/x-www-form-urlencoded”)
request.SetFormData(postData)
Message(request.Post(qbo.token_endpoint,30))

[/code]

I have also tried putting it into postData with the same results. I am new to using httpsecuresocket and exactly what needs to be placed in the header and form to link up with oauth2. i have seen other posts i believe that implement curl with shell. Trying to find that post again and might try that route.

Ok, I think this is the proper format for the http request. I duplicated what i saw from their php sdk. However, i still get invalid_client which i may know why.

[code] dim postData as new Dictionary
postData.Value(“grant_type”) = “authorization_code”
postData.Value(“code”) = app.qbo_AuthorizationCode
postData.Value(“redirect_uri”) = “my.cgi/token”

dim request as new HTTPSecureSocket
request.Secure = True
request.ConnectionType = SSLSocket.TLSv12

request.SetRequestHeader(“Accept”,“application/json”)
request.SetRequestHeader(“Authorization”,GenerateAuthorization)
request.SetRequestHeader(“Content-Type”,“application/x-www-form-urlencoded”)
request.SetFormData(postData)

Message(request.Post(qbo.token_endpoint,30))[/code]

This is the code i use for GenerateAuthorization

return "Basic " + EncodeBase64(qbo.ClientID+":"+qbo.ClientSecret)

However when i print them to a Text area they come out different. The first message is xojo generating authorization. The second message is the output i pasted from a php function that generates authorization.

Message( GenerateAuthorization) Message("Basic UTBzQmd4M1hSYVR0RjI2dWF4b3hySjRGeldUY1dheVozQkp2cjdNaU1pclZ1N01jdE86cFZTclIxVDBjd2hwSk9PNklSZXI1cm1nQzJUdGxNdGtXVGk3eFFPag==")

It looks like maybe EncodeBase64(qbo.ClientID+":"+qbo.ClientSecret) is not working properly?

Also i forgot to mention i tried this with CURLSMBS as well and i still get invalid_client.

OK, so i think i have confirmed that EncodeBase64 is indeed mixing thing up for me. I pasted the encoded authorization from the php directly into the http request and the error message changed to invalid_grant. Which is another issue i guess i’ll have to figure out.

When you look at the two EncodeBase64 strings are they different?

The same string is produced everytime with xojo and php. However, xojo seems to add something that look like chr(13) when printed to text area, php does not but produces same string.

Now i assume that this encoded string never changes so i just hard coded it into xojo from the php encoded string. While the php is able to get an access token with its encoded string, Xojo is not able to get an access token with the php encoded string and comes back with an invalid_grant error. This is another portion that i’m confused why it works for one and not the other since the encoded string never changes.

Just noticed this thread (I’m researching Quickbooks integration)…

[quote=347647:@Nicholas Henson]The same string is produced everytime with xojo and php. However, xojo seems to add something that look like chr(13) when printed to text area, php does not but produces same string.

Now i assume that this encoded string never changes so i just hard coded it into xojo from the php encoded string. While the php is able to get an access token with its encoded string, Xojo is not able to get an access token with the php encoded string and comes back with an invalid_grant error. This is another portion that i’m confused why it works for one and not the other since the encoded string never changes.[/quote]

Xojo EncodeBase64 by default will add a line break every 76 characters (Base64 standard).
SMTP (email) requires this, but HTTP tokens can be longer than 76 characters and the line breaks will fail.
There is an HTTP Authorization exception to send a single Base64 string with no breaks.

The EncodeBase64 function has an optional line length, use 0 for no line breaks.

Try this in your code EncodeBase64(qbo.ClientID+":"+qbo.ClientSecret,0)

That should still work if you need to change tokens.

I know this thread is a bit old. but I figured I’d try to finish closing the loop on it.

@John A Knight, Jr was correct as we need to use the 0 for no line breaks on the EncodeBase64 function.

Here is working code from my "HTTPSecure Socket constructor that successfully posts to refresh the QBO tokens (Step #4 from the QBO Playground)

oAuth2Socket.constructor

Sub constructor(clientId as String, clientSecret as String, redirectUrl as String, environment as St ring, prevRefreshToken as String)
Super.Constructor
// SET SOCKET INFO
Self.Secure = True
Self.port = 443
Self.ConnectionType = versiCloudApiSocket.TLSv12
// URL TO REFRESH TOKEN
Dim tokenRefreshUrlStr as String = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer "
// CREATE DICTIONARY TO POST
dim tokenRefreshDict as new Dictionary tokenRefreshDict.Value("grant_type") = "refresh_token" tokenRefreshDict.Value("refresh_token") =prevRefreshToken
// SET REQUEST HEADER
Self.SetRequestHeader("Accept","application/json") Self.SetRequestHeader("Content-Type:","application/x-www-form-urlencoded") Dim thisAuthHeader as String = generateAuthorization(clientId, clientSecret) Self.SetRequestHeader("Authorization", thisAuthHeader) Self.SetFormData(tokenRefreshDict)
-1-
// PERFORM POST Self.Post(tokenRefreshUrlStr)
End Sub

Here is my function that properly formats my “Basic Authorization” using my QBO clientID and clientSecret with EncodeBase64:

oAuth2Socket.generateAuthorization

Function generateAuthorization(clientID as String, clientSecret as String) As String Dim thisAuthHeaderStr as String = "Basic " + EncodeBase64(clientID + ":" + clientSecret, 0) return thisAuthHeaderStr End Function

@Mike Cotrone Thank you! I really appreciate you swinging back on this one…I’ve moved on from that project but your information could be incredible useful in the future. I just love the Xojo community!!!

Anytime! I am writing to their API for a couple of projects Im writing now. I found an article from a C# dev that was very useful in using QBO’s oAuth2 implementation with Xojo.

[code]1. Create an app but don’t publish it in the QBO app store. To do this login to developer.intuit.com using your QBO account. Go to ‘My Apps’ Then create an app (e.g. called ‘MyQBOApiApp’). This only needs to be done once. Leave the default redirect URL set to the OAuth2 playground as this is the only redirect URL required.

  1. Get the Production Client ID and Client Secret from the ‘Production Keys’ section of the ‘OAuth 2.0 Keys’ tab for the app. (Record these for use in your C# program as they don’t change)

  2. Goto the OAuth 2.0 playground at https://developer.intuit.com/v2/ui#/playground

  3. In step 1 ‘Get Authorization Code’ select MyQBOApiApp(Production) from the drop box list

  4. In the Select Scopes list select ‘Accounting’ if you just need to read/write data to your QBO company

  5. Click on ‘Get authorization code’

  6. Connect your QBO company to the MyQBOApiApp app

  7. In Step 2 ‘Get OAuth 2.0 token from auth code’ on the playground page click ‘Get tokens’. This will get a refresh token for your API access to your company.

  8. Skip to Step 4 ‘Refresh access token’ on the playground page. The Access Token is only usable for 59 mins so just keep the ‘Refresh Token’ as it can be used for 100 days to get new access tokens and refresh tokens. Store it somewhere that your program can read from and write to (e.g. a file or database)

  9. The realmID is available from Step 3. ‘Make API calls’. (Record this for use as it doesn’t change)[/code]

HTH

I use CDATA ODBC for QB with xojo works perfects

Thats a good note Alexis, however you are referencing Quickbooks Desktop.
The above API calls are for Quickbooks Online (Cloud Version) not Quickbooks Desktop.

ok
Look
https://www.cdata.com/drivers/qbonline/

[quote=471959:@Alexis Colon Lugo]ok
Look
https://www.cdata.com/drivers/qbonline/[/quote]

Alexis - Yes - But no - CData is a separate software service (Wrapper) for Quickbooks Online (and alot of others) charging $599 (Enterprise Desktop Subscription for QBO through their wrapper ODBC connector - https://www.cdata.com/drivers/qbonline/order/odbc/)

My code above is using the Quickbooks Online API directly (no middleware services / software) for no additional fees (outside of the QBO monthly per user fee).

Ok
Cool