Adding Parameters to VBA HTTP Post Request - vba

I want to request a token from a web service. It requires I make an HTTP "POST" request using an authorization code.
I need to include this code, among other parameters in my request.
Any detail I find online formats the request in Java as follows (all IDs are faked):
POST /services/oauth2/token HTTP/1.1
Host: "YourURL.com"
grant_type=authorization_code&code=aPrxsmIEeqM9PiQroGEWx1UiMQd95_5JUZ
VEhsOFhS8EVvbfYBBJli2W5fn3zbo.8hojaNW_1g%3D%3D&client_id=3MVG9lKcPoNI
NVBIPJjdw1J9LLM82HnFVVX19KY1uA5mu0QqEWhqKpoW3svG3XHrXDiCQjK1mdgAvhCs
cA9GE&client_secret=1955279925675241571&
redirect_uri=https%3A%2F%2Fwww.mysite.com%2Fcode_callback.jsp
How do I produce a request like this?
Below are the relevant components of my code:
Dim request As WinHttp.WinHttpRequest
Dim
client_id,
redirect_uri,
grant_type,
client_secret,
authcode,
result,
token_url,
As String
Sub testmod()
Set request = New WinHttp.WinHttpRequest
client_id = "MyClientID"
client_secret = "MyClientSecret"
grant_type = "authorization_code"
redirect_uri = "MyRedirectURI"
authcode = "MyAuthorizationCode"
token_url = "MyTokenURL" <--- No specified query string appended
With request
.Open method:="POST", Url:=token_url
''''Including POST Params with Send method''''
.Send ("{""code"":" & authcode &
",""grant_type"":authorization_code,""client_id"":" & client_id &
",""client_secret"":" & client_secret & ",""redirect_uri"":" &
redirect_uri & "}")
''''This returns error code 400 denoting a bad request''''
Debug.Print .StatusText
end with
end sub
Any idea why these parameters are causing this request to fail?

I don't know what API you are referring to, whereas there is a new API in which the oldest 'guide' is dated 'Mar' presumably 2019.
https://developer.tdameritrade.com/apis
https://developer.tdameritrade.com/guides
Wherein there is NO reference to the "&client_secret=" being needed !.
In the 'latest' API, you request the 'code' as follows directly into your browser. It is good got a very few minutes.
https://auth.tdameritrade.com/oauth?
client_id=XXXX#AMER.OAUTHAP&response_type=code&redirect_uri=https://192.168.0.100
The response appears in the browser's entry, not in the body, You have to decode the response to use the 'code'. The RefreshToken (90 days valid) & AccessToken (30 minutes valid) are used as the are returned in the ResponseText
To get the 90 day RefreshToken and the first AccessToken
This is VBA which calls Javascript.
Private Sub Get_RefreshToken() 'Good for 90 days, then needs a new 'code', see above, also get the first AccessToken which are good for 30 minutes
Dim code As String 'dcoded, not URL coded 'WAITS for the RESPONSE, NO callback
Dim shtSheetToWork As Worksheet
Set shtSheetToWork = ActiveWorkbook.Sheets("AUTH") '<<== may NEED change
With shtSheetToWork
authorizationcode = .Range(3, "C") // dump into Excel and decode by rows JSON 'split'
Dim xmlhttp As Object
Dim scriptControl As Object
Dim Response, JsonObj As Object
Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")
Set scriptControl = CreateObject("MSScriptControl.ScriptControl")
scriptControl.Language = "JScript"
authUrl = "https://api.tdameritrade.com/v1/oauth2/token"
xmlhttp.Open "Post", authUrl, False
xmlhttp.Send "{grant_type: authorization_code, authorizationcode: ,access_type: offline, client_id: .UserId, redirect_uri: .URLredirect}"
Response = scriptControl.Eval(xmlhttp.responseText)
.Range(4, "C") = Response.refresh_token 'RefreshToken
xmlhttp.setRequestHeader "Authorization", Response.refresh_token
xmlhttp.Send
MsgBox (xmlhttp.responseText)
Select Case xmlhttp.Status
Case 200
Dim i As Integer
Dim strKey As String
Dim strVal As Variant
Dim JsonData As Variant
JsonObj = JsonDate.Parse(xmlhttp.responseText)
Cells(colstr, toprow - 1) = JsonObj
i = 1
Do While Trim(Cells(i, 1)) <> ""
Name = Split(Cells(i, 1).Text, ":")
If Name = "RefreshToken" Then .RefreshToken = Name: .nextRefreshToken = DateAdd("d", 90, Now)
If Name = "AccessToken" Then .AccessToken = Name: .nextAccessToken = DateAdd("m", 30, Now)
Case 400
MsgBox (" validation problem suthorization 'CODE' ")
Stop
Case 401
MsgBox (" Invalid credentials ")
Stop
Case 403
MsgBox (" caller doesn't have access to the account ")
Stop
Case 405
MsgBox (" Response without Allow Header")
Stop
Case 500
MsgBox (" unexpected server error ")
Stop
Case 503
MsgBox ("temporary problem responding, RETRYING !! ")
' WAIT A MINUTE AND RETRY
End Select
Set xmlhttp = Nothing
Set JsonObj = Nothing
End With
End Sub
Private Sub AccessToken() 'WAITS for the RESPONSE, NO callback
Dim code As String 'dcoded, not URL coded
Dim shtSheetToWork As Worksheet
Set shtSheetToWork = ActiveWorkbook.Sheets("AUTH") '<<== may NEED change
With shtSheetToWork
Dim xmlhttp As Object
Dim scriptControl As Object
Dim Response, JsonObj As Object
Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")
Set scriptControl = CreateObject("MSScriptControl.ScriptControl")
scriptControl.Language = "JScript"
authUrl = "https://api.tdameritrade.com/v1/oauth2/token"
xmlhttp.Open "Post", authUrl, False
xmlhttp.Send "{grant_type: refresh_token, authorizationcode: .RefreshToken, access_type: , client_id: .MYUserId, redirect_uri: }"
Response = scriptControl.Eval(xmlhttp.responseText)
.AccessToken = Response.refresh_token
xmlhttp.setRequestHeader "Authorization", RefreshToken
xmlhttp.Send
'MsgBox (xmlhttp.responseText)
Select Case xmlhttp.Status
Case 200
Dim i As Integer
Private strKey As String
Private strVal As Variant
Private Data As Variant
JsonObj = Json.Parse(xmlhttp.responseText)
Cells(colstr, toprow - 1) = JsonObj
NextText = Cells(colstr, toprow - 1)
JsonObj = Nothing
i = 1
Do While Trim(Cells(i, 1)) <> ""
Name = Split(Cells(i, 1).Text, ":")
If Name = "RefreshToken" Then .RefreshToken = Name: .nextRefreshToken = DateAdd("d", 90, Now)
If Name = "AccessToken" Then .AccessToken = Name: .nextAccessToken = DateAdd("m", 30, Now)
Case 400
MsgBox (" validation problem suthorization 'CODE' ")
Stop
Case 401
MsgBox (" Invalid credentials ")
Stop
Case 403
MsgBox (" caller doesn't have access to the account ")
Stop
Case 405
MsgBox (" Response without Allow Header")
Stop
Case 500
MsgBox (" unexpected server error ")
Stop
Case 503
MsgBox ("temporary problem responding, RETRYING !! ")
' WAIT A MINUTE AND RETRY
End Select
Next i
Set xmlhttp = Nothing
End With
End Sub

Related

VBA webResponse Response.data getting error when changing type from "Dictionary" to "collection"

Here is the problem : I have the following code
Dim Client As New WebClient
Dim Request As New WebRequest
Dim Response As WebResponse
Dim responseData As Scripting.Dictionary
Request.UserAgent = VBA.Environ("USERNAME")
Request.AddHeader "AuthToken", m_token
Request.AddHeader "APIKey", m_key
Request.Method = WebMethod.HttpPost
Dim Auth As New HttpBasicAuthenticator
Auth.Setup "username", "Password"
Set Client.Authenticator = Auth
Dim Body As New Dictionary
If condition1 Then
Body.Add "status", "open"
Else
Body.Add "status", "closed"
End If
Client.BaseUrl = server_api & "Tasks/" & m_id
Set Request.Body = Body
Set Response = Client.Execute(Request)
If (Response.StatusCode = Ok) Then
Debug.Print TypeName(Response.Data) 'returns Dictionary
Set responseData = Response.Data '.Item(1)
Debug.Print "ID: " & responseData("id")
Debug.Print "message: " & responseData("message")
End If
The request is executed with success, the program has no errors, and the Response.data has the typename Dictionary, but message is :
'statut' doesn't exist in table
So I tried to fix this by changing the "status" name to the required "tableColunm" which have int32 as type in the database.
The changes applied are in the following code with results on comments:
If condition1 Then
Body.Add "tableColunm", 1 'I tried also with "1"
Else
Body.Add "tableColunm", 2 ' I tried also with "2"
End If Client.BaseUrl = server_api & "Tasks/" & m_id
Set Request.Body = Body
Set Response = Client.Execute(Request)
If (Response.StatusCode = Ok) Then
Debug.Print TypeName(Response.Data) 'returns Collection
Set responseData = Response.Data '.Item(1) ' error here, and the program crashed
Debug.Print "ID: " & responseData("id")
Debug.Print "message: " & responseData("message")
End If
Now the typename of Response.data is collection, and I think this is the reason why the program crashes
Any help ? Thanks
Finally, after adding this
For Each elt In Response.Data
Debug.Print TypeName(elt)
Next
The loop is executed only one time, outputting Dictionary. That's mean that in the second case, the dictionary is encapsulated on a collection
So I worked with elt and this solves my problem

Click on a href in VBA

I want to click on the following link
I have the class name and the line code I was trying ot use is the following:
objIE.document.getElementByClassName("msDataText searchLink").Click
This may well be a very basic question.. any guidance
Thanks a lot
Not sure if it is a duplicate question.
A good function GetHTTPResult is already available from the link. You need to just pass the url for the GET request to fetch the data. For POST request (this function will not work), you need to make a POST request with postdata.
Also there is a sample for XMLHttpRequest at link
Function GetHTTPResult(sURL As String) As String
Dim XMLHTTP As Variant, sResult As String
Set XMLHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
XMLHTTP.Open "GET", sURL, False
XMLHTTP.Send
Debug.Print "Status: " & XMLHTTP.Status & " - " & XMLHTTP.StatusText
sResult = XMLHTTP.ResponseText
Debug.Print "Length of response: " & Len(sResult)
Set XMLHTTP = Nothing
GetHTTPResult = sResult
End Function

VBA setRequestHeader "Authorization" failing

I am trying to connect to a Web Database with the following code, but it does not seem to work when automated in VBA. The login and password are fine as I can connect manually with them.
is it possible that the Object: "WinHttp.WinHttpRequest.5.1" does not work with this sort of database connection? Or maybe am I missing a parameter in my Connect sub? Any help on this matter would be greatly appreciated.
Sub Connect()
Dim oHttp As Object
Set oHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
Call oHttp.Open("GET", "http://qrdweb/mg/loan/loans.html?show=all", False)
oHttp.setRequestHeader "Content-Type", "application/xml"
oHttp.setRequestHeader "Accept", "application/xml"
oHttp.setRequestHeader "Authorization", "Basic " + Base64Encode("login123" + ":" + "pass123")
Call oHttp.send
Sheets("Sheet1").Cells(1, 1).Value = oHttp.getAllResponseHeaders
Sheets("Sheet1").Cells(1, 2).Value = oHttp.ResponseText
End Sub
Private Function Base64Encode(sText)
Dim oXML, oNode
Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
Set oNode = oXML.createElement("base64")
oNode.DataType = "bin.base64"
oNode.nodeTypedValue = StringToBinary(sText)
Base64Encode = oNode.Text
Set oNode = Nothing
Set oXML = Nothing
End Function
Private Function StringToBinary(Text)
Const adTypeText = 2
Const adTypeBinary = 1
Dim BinaryStream
Set BinaryStream = CreateObject("ADODB.Stream")
BinaryStream.Type = adTypeText
BinaryStream.Charset = "us-ascii"
BinaryStream.Open
BinaryStream.WriteText Text
'Change stream type To binary
BinaryStream.Position = 0
BinaryStream.Type = adTypeBinary
'Ignore first two bytes - sign of
BinaryStream.Position = 0
StringToBinary = BinaryStream.Read
Set BinaryStream = Nothing
End Function
The oHttp.getAllResponseHeaders displaying the getAllresponseHeaders outputs the following information:
Cache-Control: must-revalidate,no-cache,no-store
Connection: keep-alive
Date: Fri, 24 Feb 2017 17:19:54 GMT
Content-Length: 30633
Content-Type: text/html;charset=ISO-8859-1
Server: nginx/1.11.6
WWW-Authenticate: Digest realm="QRDWEB-MNM", domain="", nonce="aB5DLmvuCfok9Zo112jo4S0evgOuXntE", algorithm=MD5, qop="auth", stale=true
While the oHttp.ResponseText displaying the ResponseText outputs the following information:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 401 Server Error</title>
</head>
<body>
Edit 1
When I comment out the 3 lines of code containing: oHttp.setRequestHeader, and changing the line: Set oHttp = CreateObject("WinHttp.WinHttpRequest.5.1") by Set oHttp = CreateObject("MSXML2.XMLHTTP"), a pop up appears for a login and password. If I fill in the information the following responses are different:
The oHttp.getAllResponseHeaders displaying the getAllresponseHeaders outputs the following information:
Server: nginx/1.11.6
Date: Fri, 24 Feb 2017 18:19:02 GMT
Transfer-Encoding: chunked
Connection: keep-alive
While the oHttp.ResponseText displaying the ResponseText outputs the following information:
<html>
<head>
<title>M&M - Loan Viewer</title>
<script language="javascript" type="text/javascript">
function showTransactionComments(loanId, date, type, commentsTableWidth) {
//alert(loanId + " " + date + " " + type + " " + commentsTableWidth);
if (window.ActiveXObject) {
return;
Edit 2
I am now attempting to integrate Digest Authentication into VBA with the following sub and I get 2 possible outcomes: The first outcome is the same 401 error when using the wrong login info and the return is immediate. However, when I provide the proper login info, the operation times out... What could be causing that?
Sub digest()
Dim http As New WinHttpRequest
Dim strResponse As String
Set http = New WinHttpRequest
http.Open "GET", "http://qrdweb/mg/loan/loans.html?show=all", False
http.SetCredentials "login123", "pass123", HTTPREQUEST_SETCREDENTIALS_FOR_SERVER
http.send
Sheets("Sheet1").Cells(1, 1).Value = http.getAllResponseHeaders
Sheets("Sheet1").Cells(1, 2).Value = http.ResponseText
http.Open "PROPFIND", "http://qrdweb/mg/loan/loans.html?show=all", False
http.send
End Sub
Per the Microsoft docs, the JScript example, it looks like authentication requires two sucessive Open/Send pairs on the same connection. The first tells the HTTP request object that Digest authentication is required, and the second actually does it. Try this (not tested):
Sub digest()
Dim http As WinHttpRequest ' *** Not "New" - you do it below
Dim strResponse As String
Set http = New WinHttpRequest
http.Open "GET", "http://qrdweb/mg/loan/loans.html?show=all", False
http.Send ' *** Try it without authentication first
if http.Status <> 401 then Exit Sub ' *** Or do something else
http.Open "GET", "http://qrdweb/mg/loan/loans.html?show=all", False
' *** Another Open, same as the JScript example
http.SetCredentials "login123", "pass123", HTTPREQUEST_SETCREDENTIALS_FOR_SERVER
http.Send
MsgBox CStr(http.Status) & ": " & http.StatusText ' *** Just to check
Sheets("Sheet1").Cells(1, 1).Value = http.getAllResponseHeaders
Sheets("Sheet1").Cells(1, 2).Value = http.ResponseText
' *** Not sure what these two lines are for --- I have commented them out
'http.Open "PROPFIND", "http://qrdweb/mg/loan/loans.html?show=all", False
'http.send
End Sub

PayPal IPN issue for notify

I have set up a PDT form and that is working and collecting payments and then returning to the appropriate url with the follow parameters
tx=1******X&st=Completed&amt=0.02&cc=GBP&cm=&item_number=NA
I am using the follow example code:
Dim strSandbox As String = "https://www.sandbox.paypal.com/cgi-bin/webscr"
Dim strLive As String = "https://www.paypal.com/cgi-bin/webscr"
Dim req As HttpWebRequest = CType(WebRequest.Create(strLive), HttpWebRequest)
'Set values for the request back
req.Method = "POST"
req.ContentType = "application/x-www-form-urlencoded"
Dim Param() As Byte = Request.BinaryRead(HttpContext.Current.Request.ContentLength)
Dim strRequest As String = Encoding.ASCII.GetString(Param)
strRequest = strRequest & "&cmd=_notify-validate"
req.ContentLength = strRequest.Length
'for proxy
'Dim proxy As New WebProxy(New System.Uri("http://url:port#"))
'req.Proxy = proxy
'Send the request to PayPal and get the response
Dim streamOut As StreamWriter = New StreamWriter(req.GetRequestStream(), Encoding.ASCII)
streamOut.Write(strRequest)
streamOut.Close()
Dim streamIn As StreamReader = New StreamReader(req.GetResponse().GetResponseStream())
Dim strResponse As String = streamIn.ReadToEnd()
streamIn.Close()
If strResponse = "VERIFIED" Then
'check the payment_status is Completed
'check that txn_id has not been previously processed
'check that receiver_email is your Primary PayPal email
'check that payment_amount/payment_currency are correct
'process payment
lit1.Text = "verified"
ElseIf strResponse = "INVALID" Then
'log for manual investigation
lit1.Text = "invalid"
Else
'Response wasn't VERIFIED or INVALID, log for manual investigation
lit1.Text = "unknown"
End If
lit1.Text = lit1.Text & "<br /><br />" & strRequest.ToString
I am only getting an invalid response so I tried to see what was being sent to Paypal but its only sending &cmd=_notify-validate and not rest of the parameters.
So I manually added to the parameters but still only got invalid.
Could someone please assist with what I am missing? The payment was successful
Thanks
I sorted it, I didnt understand the process but do now

VBA WinHttp request:parameter is incorrect (error 80070057)

I have this script to automatically fetch Google Analytics results, it has worked fine for over a year. All of the sudden it stopped working.
I'm getting error 80070057: parameter is incorrect
This is the code. And yes, I'm using a proxy.
The error happens at the first SetRequestHeader
Dim WinHttpReq As WinHttp.WinHttpRequest
' Create an instance of the WinHTTPRequest ActiveX object.
Set WinHttpReq = New WinHttpRequest
' Assemble an HTTP Request.
WinHttpReq.Open "GET", url, False
WinHttpReq.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, "http://webproxy.vum.be:8080"
WinHttpReq.SetRequestHeader "Authorization", "GoogleLogin Auth=" & auth
WinHttpReq.SetRequestHeader "GData-Version", 2
' Send the HTTP Request.
WinHttpReq.Send
' Put status and content type into status text box.
strStatus = WinHttpReq.STATUS & " - " & WinHttpReq.StatusText
'Debug.Print "Status: " & strStatus
If Body = True Then
get_url_google = WinHttpReq.ResponseText
Else
get_url_google = strStatus
End If
It was Google's fault. The "auth" variable was misformed, during the authentication procedure google was asking for a captcha.