Access (and authenticate at) Zendesk web API with Excel VBA - json

I'm trying to use a web API with Excel VBA.
In the API instructions it is written:
Using cURL
curl https://{subdomain}.zendesk.com/api/v2/users/create_or_update.json \
-d '{"user": {"name": "Roger Wilco", "email": "roge#example.org"}}' \
-H "Content-Type: application/json" -X POST \
-v -u {email_address}:{password}
Link to the API itself (Create or Update User) https://developer.zendesk.com/rest_api/docs/support/users#create-or-update-user
This is my code:
Public Function PostJsonRequest() As String
Dim strURL As String
Dim strParse() As String
Dim jsonStr As String
Dim hreq As Object
Dim tixScript As Object
On Error GoTo Er
Set hreq = CreateObject("MSXML2.XMLHTTP")
strURL = "https://subdomain.zendesk.com/api/v2/users/create_or_update"
hreq.Open "POST", strURL, 0, "username/token", "token"
hreq.setRequestHeader "User-Agent", "Chrome"
hreq.setRequestHeader "Content-Type", "application/json"
hreq.setRequestHeader "Accept", "application/json"
hreq.setRequestHeader "-v -u {MyEmail}:{MyPassword}"
jsonStr = "-d '{""user"": {""name"": ""Roger Wilco"", ""email"": ""roge#example.org""}}'"
hreq.Send jsonStr
MsgBox hreq.responseText
Exit Function
Er:
MsgBox "Error - " & Err.Number & " - " & Err.Description
End Function
In the Email and Password line I get this error:
Error - 450 - Wrong number of arguments or invalid property assignment

This is not valid hreq.setRequestHeader "-v -u {MyEmail}:{MyPassword}"
Try basic authentication instead
hreq.setRequestHeader "Authorization", "Basic dXNlcjpwYXNzd29yZA=="
where dXNlcjpwYXNzd29yZA== is the base64 encoded {MyEmail}:{MyPassword} string.
For example:
Dim username As String
username = "user123"
Dim password As String
password = "abc123"
hreq.setRequestHeader "Authorization", "Basic " & EncodeBase64(username & ":" & password)
Where the base64 encoding function works like this:
Private Function EncodeBase64(ByVal plainText As String) As String
Dim bytes() As Byte
Dim objXML As Object 'MSXML2.DOMDocument60
Dim objNode As Object 'MSXML2.IXMLDOMNode
bytes = StrConv(plainText, vbFromUnicode)
Set objXML = CreateObject("MSXML2.DOMDocument.6.0")
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.nodeTypedValue = bytes
EncodeBase64 = objNode.Text
Set objNode = Nothing
Set objXML = Nothing
End Function
Also make sure you only send the JSON part without the -d '…':
jsonStr = "{""user"": {""name"": ""Roger Wilco"", ""email"": ""roge#example.org""}}"
Finally a more cosmetic thing than an issue:
hreq.setRequestHeader "User-Agent", "Chrome"
Either set your user agent string to fake a real user agent, for a current chrome it would look like:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
Faking a user agent is to make the website think you are surfing with a Chrome for example. For the API this is not necessary I guess, so you can set it to something generic like:
hreq.setRequestHeader "User-Agent", "MyVBAProject Version x.y.z Windows 10 using MSXML2.XMLHTTP"
to show the website clearly which type of application you are.
At least don't set it to "Chrome" as this is just confusing as Chrome would never use that user agent.

Related

Getting unsupported_grant_type when exchanging code for a token

Using VBA, I am able to authenticate the user and obtain 'code' successfully using my sandbox account. However, when I attempt to exchange the permission token for an access token, I get status code 400, Bad Request (unsupported_grant_type). I searched for similar problems and tried many suggestions to no avail. I have been successful in using the implicit grant process, but would like to now switch to code grant. I validated the Base64 conversion using an online tool. It worked fine. The process looks very simple and straight forward. Any help is much appreciated.
The VBA code I'm using follows:
strURL = "https://account-d.docusign.com/oauth/token"
strAuthorization = Base64EncodeString(gstrIntegrationKey & ":" & gstrSecretKey)
Set objJSON = New Dictionary
objJSON.Add "grant_type", "authorization_code"
objJSON.Add "code", strCode
strJSON = JsonConverter.ConvertToJson(objJSON)
Set objHTTP = New MSXML2.XMLHTTP60
objHTTP.Open "POST", strURL, False
objHTTP.setRequestHeader "Content-Type: ", "application/x-www-form-urlencoded"
objHTTP.setRequestHeader "Accept: ", "application/json"
objHTTP.setRequestHeader "Authorization: ", "Basic " & strAuthorization
objHTTP.send strJSON
Do Until objHTTP.ReadyState = 4
DoEvents
Loop
strResponse = Replace(objHTTP.responseText, "null", """null""")
If objHTTP.Status <> 200 Then
If Not DocuSignErr(strResponse, objHTTP.Status, objHTTP.statusText) Then Stop
GoTo FailedExit
End If
The body should be form URL encoded not JSON encoded. Instead of using the Dictionary and running it through JsonConverter.ConvertToJson, you should encode it in as a form (e.g., value1=a&value2=b). So, you can do something like this:
strURL = "https://account-d.docusign.com/oauth/token"
strAuthorization = Base64EncodeString(gstrIntegrationKey & ":" & gstrSecretKey)
Set objHTTP = New MSXML2.XMLHTTP60
objHTTP.Open "POST", strURL, False
objHTTP.setRequestHeader "Content-Type: ", "application/x-www-form-urlencoded"
objHTTP.setRequestHeader "Accept: ", "application/json"
objHTTP.setRequestHeader "Authorization: ", "Basic " & strAuthorization
objHTTP.send "grant_type=authorization_code&code=" & strCode
...

Passing API key and parameters using VBA in a POST request

I have been trying to wrap my head around this VBA-Web doc http://vba-tools.github.io/VBA-Web/docs/ in order to pass auth_key and other parameters in a post request. I understand the concept of encoding the auth_key as explained here How to pass API key in VBA for Get and Post Request?. But I need help to include all the parameters below in VBA.
UPDATE:
I was able to make QHarr's code below work. But I'm still finding it hard to use my own curl parameters below. I've tried using EncodeBase64(apikey) but I'm not there yet.
Public Sub GetResults()
Dim data As String, json As Object '< VBE > Tools > References > Microsoft Scripting Runtime
data = "{""domainNames"":[""google.com""]}"
With CreateObject("WinHttp.WinHttpRequest.5.1")
.Open "POST", "https://api.dev.name.com/v4/domains:checkAvailability", False
.setRequestHeader "User-Agent", "Mozilla/5.0"
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
.setRequestHeader "Authorization", "Basic " + _
EncodeBase64("username" + ":" + "Token")
.send data
Set json = JsonConverter.ParseJson(.responseText)
Dim result As Object
For Each result In json("results")
Debug.Print result("domainName")
Next
End With
End Sub
Function EncodeBase64(text As String) As String
Dim arrData() As Byte
arrData = StrConv(text, vbFromUnicode)
Dim objXML As MSXML2.DOMDocument60
Dim objNode As MSXML2.IXMLDOMElement
Set objXML = New MSXML2.DOMDocument60
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.nodeTypedValue = arrData
EncodeBase64 = Application.Clean(objNode.text)
Set objNode = Nothing
Set objXML = Nothing
End Function
Here is the API doc - https://cloud.ibm.com/apidocs/
Feature request:
curl -X POST \
-H "Content-Type: application/json" \
-u "apikey:{apikey}" \
-d #parameters.json \
"{url}/v1/analyze?version=2019-07-12"
Example parameter:
{
"features": {
"semantic_roles": {}
},
"text": "IBM has one of the largest workforces in the world"
}

CURL Equivalent to POST JSON data using VBA

I know this is similar to some previously asked questions, but something is still not working for me. How can the following command:
curl -X POST --data #statements.json -H "Content-Type: application/json" --user username:password -H "x-experience-api-version: 1.0.0" https://MYLRS.waxlrs.com/TCAPI/statements
be replicated in VBA?
Extra Information:
This relates to a Hosted TIN CAN (xAPI) Learning Record Store called WaxLRS (by SaltBox). The above example comes from here:
http://support.saltbox.com/support/solutions/articles/1000083945-quick
I have an account (free tinkerers account, no CC required to setup) and have generated what I believe to be the required username & password combination. The credentials are termed 'Identifier' & 'Password' and appear under a heading: Basic Authentication Credentials.
No matter what I do I get an error message:
<html>
<head><title>Unauthorized</title></head>
<body>
<h1>Unauthorized</h1>
<p>This server could not verify that you are authorized to
access the document you requested. Either you supplied the
wrong credentials (e.g., bad password), or your browser
does not understand how to supply the credentials required.
<br/>
<!-- --></p>
<hr noshade>
<div align="right">WSGI Server</div>
</body>
</html>
I believe that the example is expecting the JSON payload to be obtained from a file, but I am loading it into a string. I don't expect this to be contributing to the problem, I have compared my string with the example provided using NP++ Compare and it matches.
My code so far is:
url = "https://xxxxxxx.waxlrs.com/TCAPI/statements"
Set pXmlHttp = CreateObject("WinHttp.WinHttpRequest.5.1") 'MSXML2.XMLHTTP")
pXmlHttp.Open "POST", url, False
pXmlHttp.setRequestHeader "Content-Type", "application/json"
'pXmlHttp.setRequestHeader "Authorization", "Basic xxxxxxt8wfB6JYerYCz:xxxxxx1FOd29J1s6G2"
pXmlHttp.SetCredentials "xxxxxxt8wfB6JYerYCz", "xxxxxx1FOd29J1s6G2", 0
pXmlHttp.setRequestHeader "x-experience-api-version", "1.0.0"
pXmlHttp.send (stringJSON)
Set pHtmlObj = CreateObject("htmlfile")
pHtmlObj.body.innerHTML = pXmlHttp.responseText
apiWaxLRS = pXmlHttp.responseText
Questions/Answers that helped:
Send a JSON string to a RESTful WS from Classic ASP
https://stackoverflow.com/a/17063741/3451115
How to POST JSON Data via HTTP API using VBScript?
But, I'm still at a loss as to how to replicate the CURL statement in VBA
Try to make basic authorization as shown in the below example:
Sub Test()
sUrl = "https://xxxxxxx.waxlrs.com/TCAPI/statements"
sUsername = "*******************"
sPassword = "******************"
sAuth = TextBase64Encode(sUsername & ":" & sPassword, "us-ascii")
With CreateObject("WinHttp.WinHttpRequest.5.1")
.Open "POST", sUrl, False
.setRequestHeader "Content-Type", "application/json"
.setRequestHeader "Authorization", "Basic " & sAuth
.setRequestHeader "x-experience-api-version", "1.0.0"
.send (stringJSON)
apiWaxLRS = .responseText
End With
End Sub
Function TextBase64Encode(sText, sCharset)
Dim aBinary
With CreateObject("ADODB.Stream")
.Type = 2 ' adTypeText
.Open
.Charset = sCharset
.WriteText sText
.Position = 0
.Type = 1 ' adTypeBinary
aBinary = .Read
.Close
End With
With CreateObject("Microsoft.XMLDOM").CreateElement("objNode")
.DataType = "bin.base64"
.NodeTypedValue = aBinary
TextBase64Encode = Replace(Replace(.Text, vbCr, ""), vbLf, "")
End With
End Function

Handle Special Characters in VBA on ms Access

I'm writing a VBA code to check for access for my Database:
The code check if I have privilege to connect to a web server so it grants me access to the DB.
Function WebVer(ByVal StrUserName As String, ByVal StrPassword As String) As String
Dim Access As String
Dim objHTTP As Object
Dim URL As String
Dim Response As String
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URL = "http://myweb.com/authenticator?app=WebDNC_server&service=authenticate&userid=" & StrUserName & "&password=" & StrPassword
objHTTP.Open "GET", URL, False
objHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
objHTTP.Send ("")
LDAPResponse = UCase(objHTTP.responseText)
If Response Like "*BAD*" Then
WebVer= "BAD PASSWORD"
ElseIf Response Like "*PASS*" Then
WebVer= "PASS"
ElseIf Response Like "*USERID*" Then
WebVer= "USERID Not RECOGNIZED"
Else
WebVer= "CONNECTION ERROR"
End If
End Function
Now everything is going fine except that if the user uses special characters in the password it returns BAD Password. I think there is a problem on how VBA handles Special characters but still do not know how to solve it. Any help would be appreciated.
I'm pretty sure you have to URL-encode the username and password.
See: How can I URL encode a string in Excel VBA?

how can I http post a JSON file using an excel on both Windows and Mac

I currently have a spreadsheet where a macro creates a JSON string and posts it to a web service using HTTP. On windows this code works fine for this:
Private Sub pvPostString(sUrl As String, sString As String, sFileName As String, Optional ByVal bAsync As Boolean)
Const STR_BOUNDARY As String = "3fbd04f5-b1ed-4060-99b9-fca7ff59c113"
Dim nFile As Integer
Dim baBuffer() As Byte
Dim sPostData As String
Dim connUrl As String
sPostData = sString
'--- prepare body
sPostData = "--" & STR_BOUNDARY & vbCrLf & _
"Content-Disposition: form-data; name=""uploadfile""; filename=""" & Mid$(sFileName, InStrRev(sFileName, "\") + 1) & """" & vbCrLf & _
"Content-Type: application/octet-stream" & vbCrLf & vbCrLf & _
sPostData & vbCrLf & _
"--" & STR_BOUNDARY & "--"
'--- post
With CreateObject("MSXML2.XMLHTTP")
.Open "POST", sUrl, bAsync
.SetRequestHeader "Content-Type", "multipart/form-data; boundary=" & STR_BOUNDARY
.Send pvToByteArray(sPostData)
End With
End Sub
However on the latest Mac Excel I get an error "ActiveX component can't create object". This makes sense as MSXML2.XMLHTTP is a Microsoft solution, however it means I need to find a replacement function.
I've done lots of googling on this matter and from what I have read I may be able to achieve this using query tables. However, I have tried all sorts of configurations but with no joy. For example if I try the following then I get the error "Invalid web query"
With ActiveSheet.QueryTables.Add(Connection:=connUrl, Destination:=Range("C30"))
.PostText = myJSONString
.RefreshStyle = xlOverwriteCells
.SaveData = True
.Refresh
End With
This makes sense as JSON isn't valid post text, though at the same time posting a lengthy JSON file as post text doesn't really seem like the right solution.
Ideally I would like to post the JSON as a file so that it can be referenced on the server by $_FILES[]. Though from what I've read it isn't clear on how to do this (or if it is possible at all).
tldr; Ultimately my objective with this is to have a function that allows me to post a lengthy JSON string via http that will work on both Windows and Mac. I would really appreciate any help on this.
VBA-Web (previously Excel-REST) supports both Windows in Mac in v4.0.0 and allows you to GET, POST, PUT, PATCH, and DELETE from VBA. I haven't tried it with file uploads, so I'm not sure it will work in your case, but I'd give it a try. Here's a sample:
' Replace with the following
' With CreateObject("MSXML2.XMLHTTP")
' .Open "POST", sUrl, bAsync
' .SetRequestHeader "Content-Type", "multipart/form-data; boundary=" & STR_BOUNDARY
' .Send pvToByteArray(sPostData)
' End With
' Client for executing requests
Dim Client As New WebClient
' Generally set Client.BaseUrl here, but it's not required
' Request for setting request details
Dim Request As New WebRequest
Request.Method = WebMethod.HttpPost
Request.Resource = sUrl
Request.ContentType = "multipart/form-data; boundary=" & STR_BOUNDARY
' Execute request and store response
Dim Response As WebResponse
Set Response = Client.Execute(Request)