-1

I am using Postman to send in an authorization request to google to retrieve an access token. When I enter all the required information on the Authorization tab and click on the Get New Access Token button, I get a response back from google with an access token. This proves that the data I am sending in is valid and my project is set up properly on google. Now, I need to convert this request to a VBA request.

When I view the Postman log I can see the data that Postman sends to Google. This is what I see:

enter image description here

And this is the response that google sends back:

enter image description here

This is the VBA code that I am using to try to replicate the Postman call (I have the redirect url set to my local machine which is in the list of approved redirect url's on my google project):

Dim sClient_ID As String
Dim sClient_Secret As String
Dim sGrant_Type As String
Dim sCode As String
Dim sRedirect_URI As String
sClient_ID = "{the client id that google provided to me}"
sClient_Secret = "{the client secret that google provided to me}"
sGrant_Type = "authorization_code"
sCode = "4/0AWtgzh75ZFps55t9vPx-gm_rm8W_uyWQbZwBF1qTLthpUuPjaAXBr9iywT-RweVvagcGPg"
sRedirect_URI = "https://localhost:8080"

' build the json string which will be sent to get the google access token

Dim a As New Scripting.Dictionary

a.Add "grant_type", sGrant_Type
a.Add "code", sCode
a.Add "redirect_uri", sRedirect_URI
a.Add "client_id", sClient_ID
a.Add "client_secret", sClient_Secret

Dim Json_Get_Access_Token As String
Json_Get_Access_Token = JsonConverter.ConvertToJson(a, Whitespace:=" ")

' send the json string via POST
Set httpCall = CreateObject("MSXML2.ServerXMLHTTP")
Dim sTokenURL As String
sTokenURL = "https://oauth2.googleapis.com/token"
httpCall.Open "POST", sTokenURL, False
httpCall.setRequestHeader "Content-Type", "application/json;charset=UTF-8"
httpCall.Send Json_Get_Access_Token
Dim sReturnToken As String
sReturnToken = httpCall.responseText

When I run the code and look at the value is sReturnToken, I see this:

{
  "error": "invalid_grant",
  "error_description": "Bad Request"
}

Any idea what I'm not setting up properly? Thank you.

Christian Baumann
  • 3,188
  • 3
  • 20
  • 37
Jonathan Small
  • 1,027
  • 3
  • 18
  • 40
  • Your postman screenshot shows the POST request content-type as `application/x-www-form-urlencoded` but your VBA is using a json-formatted request body? – Tim Williams Feb 08 '23 at 21:18

1 Answers1

0

EDIT:

You can actually send the requests as json or encoded URL

Send request as JSON

Set Content-Type to application/json and convert the a dictinary to json

Dim Json_Get_Access_Token As String
Json_Get_Access_Token = JsonConverter.ConvertToJson(a, Whitespace:=" ")
'...
httpCall.Send Json_Get_Access_Token 
'...

Send request as Encoded URL

Set Content-Type to application/x-www-form-urlencoded and concatenate the values of the a dictionary like this: data=value&data2=value2, each value must be encoded with WorksheetFunction.EncodeURL function that only works in Excel 2013+ if you have an older version or non-Excel app then use this function

Dim strQueryString as String
For Each vKey In a.Keys()
   strQueryString = strQueryString & vKey & "=" & WorksheetFunction.EncodeURL(a(vKey)) & "&"
Next
' Remove last &
strQueryString = Left(strQueryString, Len(strQueryString) - 1) 
'...
httpCall.Send strQueryString 
'...

Here more info

Tested output:

{
  "access_token": "ya29.xxx",
  "expires_in": 3599,
  "refresh_token": "1//xxx",
  "scope": "https://www.googleapis.com/auth/calendar.events.readonly",
  "token_type": "Bearer"
}
tttony
  • 4,944
  • 4
  • 26
  • 41
  • I made the changes as you suggested but now I am getting a run-time error '13' type mismatch error on the Json_Get_Access_Token = Join(a, '&') statement – Jonathan Small Feb 08 '23 at 22:10
  • Dictionary values need to be URL-encoded? – Tim Williams Feb 08 '23 at 22:42
  • @tttony - I implemented your changes (I am running my code from Outlook, not Excel so I copied one of the url encoding functions from the link you provided) and now I get an error stating invalid_grant. I took another look at https://developers.google.com/identity/protocols/oauth2/web-server?hl=en#httprest_3. Look at step 5 where they give a sample request snippet. In the value for code they show 4/P7q...... and in the value for redirect_uri they show https%3A//..... Does this imply that they need just the redirect_uri URL-encoded and the other fields should not be? – Jonathan Small Feb 09 '23 at 14:39
  • @tttony - I did some more digging and I dont think its an issue with my code. I went into the google Oauth playground and set up a test using my Oauth credentials. Then I set the scope and authorized the API. Then I exchanged the code for tokens and got an access token back. The playground shows the request and the response. I copied the request and pasted it into my VBA code into the Json_Get_Access_Token variable and then sent that to google with the httpCall.Send. I get back an error in the response that says { "error": "invalid_grant", "error_description": "Bad Request"}. strange – Jonathan Small Feb 09 '23 at 15:06
  • @tttony - the only thing I can think of is that maybe you are running in an excel environment and I'm running in an Outlook environment and that maybe the resulted encoded string that you generate is different than the one I generate. Could that be the issue? Your code makes use of the WorksheetFunction.EncodeURL which I do not have access to. When I try to use that, I get an object required error. – Jonathan Small Feb 09 '23 at 16:31
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251765/discussion-between-jonathan-small-and-tttony). – Jonathan Small Feb 09 '23 at 17:03