I have stumbled upon an issue in the b64 encoding function that broke the Basic Authentication when using a longer password e.g. API token.
I share in this post how I do REST API calls with a Basic Authentication example for Jira including the fix for this issue.
The function to create the Basic Authentication String looks like this:
b64 Encoding
For a Basic Authentication you need to encode as binary64 the string passed in the Request Header.
I had a bug in the encoding function I was using.
(This was triggering an error "setRequestHeader 0x80070057 - The parameter is incorrect." because the encoded string contained line breaks)
I have found the fix in this blog forum Base64 encoder/decoder for Binary data - AutoHotkey Community
The fix is also available in my repo here: https://github.com/tdalon/ahk/blob/main/Lib/b64Encode.ahk
Basic Auth for Jira
I use to configure the API token for the Jira authentication in an INI File with following Json structure:
[Jira]
JiraAuth=[{"url":"<YourJiraUrl>","username":"<YourJiraEmail>","apitoken":"<YourApitoken>"}]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Jira_BasicAuth(sUrl:="",sToken:="") { | |
; Get Auth String for basic authentification | |
; sAuth := Jira_BasicAuth(sUrl:="",sToken:="") | |
; Default Url is Setting JiraRootUrl | |
; Calls: b64Encode | |
If !RegExMatch(sUrl,"^http") ; missing root url or default url | |
sUrl := Jira_GetRootUrl() . sUrl | |
If (sToken = "") { | |
; If Cloud | |
If InStr(sUrl,".atlassian.net") { | |
; Read Jira PowerTools.ini setting | |
If !FileExist("PowerTools.ini") { | |
PowerTools_ErrDlg("No PowerTools.ini file found!") | |
return | |
} | |
IniRead, JiraAuth, PowerTools.ini,Jira,JiraAuth | |
If (JiraAuth="ERROR") { ; Section [Jira] Key JiraAuth not found | |
PowerTools_ErrDlg("JiraAuth key not found in PowerTools.ini file [Jira] section!") | |
return | |
} | |
JsonObj := Jxon_Load(JiraAuth) | |
For i, inst in JsonObj | |
{ | |
url := inst["url"] | |
If InStr(sUrl,url) { | |
JiraToken := inst["apitoken"] | |
If (JiraToken="") { ; Section [Jira] Key JiraAuth not found | |
PowerTools_ErrDlg("ApiToken is not defined in PowerTools.ini file [Jira] section, JiraAuth key for url '" . url . "'!") | |
return | |
} | |
JiraUserName := inst["username"] | |
break | |
} | |
} | |
If (JiraToken="") { ; Section [Jira] Key JiraAuth not found | |
RegExMatch(sUrl,"https?://[^/]*",sRootUrl) | |
PowerTools_ErrDlg("No instance defined in PowerTools.ini file [Jira] section, JiraAuth key for url '" . sRootUrl . "'!") | |
return | |
} | |
} Else { ; server | |
JiraToken := Jira_GetPassword() | |
If (JiraToken="") ; cancel | |
return | |
} | |
} | |
If (JiraUserName ="") | |
JiraUserName := Jira_GetUserName() | |
If (JiraUserName ="") | |
return | |
sAuth := b64Encode( JiraUserName . ":" . JiraToken) | |
return sAuth | |
} ; eofun |
API Requests
Doing REST API Calls can be then done as shown in following functions:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ---------------------------------------------------------------------- | |
Jira_Get(sUrl,sPassword:=""){ | |
; Syntax: sResponseText := Jira_Get(sUrl,sPassword*) | |
; sPassword Password for server or Api Token for cloud | |
; Calls: Jira_BasicAuth | |
If !RegExMatch(sUrl,"^http") ; missing root url or default url | |
sUrl := Jira_GetRootUrl() . sUrl | |
sAuth := Jira_BasicAuth(sUrl,sPassword) | |
Clipboard := sAuth | |
If (sAuth="") | |
return | |
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1") | |
WebRequest.Open("GET", sUrl, false) ; Async=false | |
sAuth := "Basic " . sAuth | |
WebRequest.setRequestHeader("Authorization", sAuth) | |
WebRequest.setRequestHeader("Content-Type", "application/json") | |
WebRequest.Send() | |
return WebRequest.responseText | |
} | |
; ---------------------------------------------------------------------- | |
Jira_Post(sUrl,sBody:="",sPassword:=""){ | |
; Syntax: sResponseText := Jira_Post(sUrl,sBody,sPassword*) | |
; Calls: Jira_BasicAuth | |
If !RegExMatch(sUrl,"^http") ; missing root url or default url | |
sUrl := Jira_GetRootUrl() . sUrl | |
sAuth := Jira_BasicAuth(sUrl,sPassword) | |
If (sAuth="") | |
return | |
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1") | |
WebRequest.Open("POST", sUrl, false) ; Async=false | |
WebRequest.setRequestHeader("Authorization", "Basic " . sAuth) | |
WebRequest.setRequestHeader("Content-Type", "application/json") | |
If (sBody = "") | |
WebRequest.Send() | |
Else | |
WebRequest.Send(sBody) | |
WebRequest.WaitForResponse() | |
return WebRequest.responseText | |
} | |
; ---------------------------------------------------------------------- | |
Jira_WebRequest(sReqType,sUrl,sBody:="",sPassword:=""){ | |
; Syntax: WebRequest := Jira_WebRequest(sReqType,sUrl,sBody:="",sPassword:="") | |
; Output WebRequest with fields Status and ResponseText | |
; Calls: Jira_BasicAuth | |
If !RegExMatch(sUrl,"^http") ; missing root url or default url | |
sUrl := Jira_GetRootUrl() . sUrl | |
sAuth := Jira_BasicAuth(sUrl,sPassword) | |
If (sAuth="") | |
return | |
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1") | |
WebRequest.Open(sReqType, sUrl, false) ; Async=false | |
WebRequest.setRequestHeader("Authorization", "Basic " . sAuth) | |
WebRequest.setRequestHeader("Content-Type", "application/json") | |
If (sBody = "") | |
WebRequest.Send() | |
Else | |
WebRequest.Send(sBody) | |
WebRequest.WaitForResponse() | |
return WebRequest | |
} |