Hello community,
Just wanted to share..
While requested to access some service I was told to authenticate my request using OAuth 1.0 (revision A) with
In the end the most helpful thing to do was to refer the docs here :
lets declare some parameters - required to the sign process: (not real values ofc...)
In my case, I also use encoded parameters in Authorization header
Knowing all this data, we can see in the code snippet in Postman the generated result for our sign under the oauth_signature param. in this case the result is mdmQ6T%2BMSgWnKaRfjms4U89iBG9tgDudg15Q7%2FMNGwk%3D
So lets construct our Object Script version to get this result
//params
set nonce = "s3fr5drk83kde3" //..getNonce() // random string
set timestamp = 1696497844 //$zdatetime($horolog,-2)
set consumerKey = "cons123key321"
set customerSecret = "conssecret123"
set signatureMethod = "HMAC-SHA256"
set version = "1.0"
set token = "acc999token456"
set tokenSecret = "toksec234234"
set httpMethod = "GET"
set url = "https://www.somerandom123.com/noplace/"
ObjectScriptObjectScript
next we need to construct the message to sign: The documentations dictate the following structure :
lets start with the params: as stated in the docs we need to populate and sort "oauth_*" variables delimited with '&' ($char(38))
and the result must be encoded (uri).
//params string build
//sorted array (required !), as vectores are dictionary sorted for strings
//all is good
set dictionaryArray("oauth_consumer_key") = consumerKey
set dictionaryArray("oauth_nonce") = nonce
set dictionaryArray("oauth_signature_method") = signatureMethod
set dictionaryArray("oauth_timestamp") = timeStamp
set dictionaryArray("oauth_token") = token
set dictionaryArray("oauth_version") = version
// messy but ok
set pos = 0
set paramString = ""
set key = ""
for {
set key = $order(dictionaryArray(key),1,value)
quit:(key = "")
set $piece(paramString,"&",$increment(pos)) = key_"="_value
}
ObjectScriptObjectScript
keep in mind that the service provider can ask for some additional params to accompany the "oauth_*" , just add them to the array...
to achieve the required encode, in JavaScript, the use is :
let myEncodedMessage = encodeURIComponent(myMessage);
JavaScriptJavaScript
in Object Script it is a bit different - most likely due to my cache version.
set paramStringUtf8 = $zconvert(paramString,"O","UTF8")
set encodedParamString = $zconvert(paramStringUtf8,"O","URL")
ObjectScriptObjectScript
but the result of the two command lines above will not be sufficient if we have "/" char in the message string. This off course will happen in the encoded URL part of our message to sign.
e.g.
set urlUtf8 = $zconvert(url,"O","UTF8")
set encodedUrl = $zconvert(urlUtf8,"O","URL")
set encodedUrlEscape = $replace(encodedUrl,"/","%2F")
write !,"url = "_url,!," utf8 = "_urlUtf8,!," encodedUrl ="_encodedUrl,!," encodedUrlEscape ="_encodedUrlEscape
/*output---------------------------------------------------------
url = https://www.somerandom123.com/noplace/
utf8 = https://www.somerandom123.com/noplace/
encodedUrl =https%3A//www.somerandom123.com/noplace/
encodedUrlEscape =https%3A%2F%2Fwww.somerandom123.com%2Fnoplace%2F
----------------------------------------------------------------*/
ObjectScriptObjectScript
so I had to forcefully replace "/" to the encoded "%2F" to make sure the result is right.
set encodedUrlEscape = $replace(encodedUrl,"/","%2F") //required
ObjectScriptObjectScript
and after we encoded our params and url the constructed message to sign will look like :
set baseString = httpMethod_"&"_encodedUrlEscape_"&"_encodedParamsString
write !,baseString
GET&https%3A%2F%2Fwww.somerandom123.com%2Fnoplace%2F&oauth_consumer_key%3Dcons123key321%26oauth_nonce%3Dcons123key321%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1696497844%26oauth_token%3Dacc999token456%26oauth_version%3D1.0
ObjectScriptObjectScript
with our message constructed (baseString) we need to construct the key that will sign it.
the structure is:
set cipherKey = customerSecret_"&"_tokenSecret
ObjectScriptObjectScript
sign the message:
set HMACSHA256 = $system.Encryption.HMACSHA(256,baseString,cipherKey) //the HMACSHA256 will result in chars like stream , so we need to encode it to base64.
set HMACSHA256Base64 = $system.Encryption.Base64Encode(HMACSHA256)
write !,HMACSHA256Base64
mdmQ6T+MSgWnKaRfjms4U89iBG9tgDudg15Q7/MNGwk=
//and if we want to Encode parameters in Authorization header
set HMACSHA256Base64Url = $zconvert(HMACSHA256Base64,"O","URL")
write !,HMACSHA256Base64Url
mdmQ6T%2BMSgWnKaRfjms4U89iBG9tgDudg15Q7/MNGwk%3D
ObjectScriptObjectScript
and we got the required value to put in "oauth_signature" param.
all that left is to construct the Authorization header and run the http request to the required service. keep in mind that here the param values are quoted.
full example of our steps:
set nonce = "s3fr5drk83kde3" //..getNonce() // need to be random unique
set timeStamp = 1696497844 //$zdatetime($horolog,-2)
set consumerKey = "cons123key321"
set customerSecret = "conssecret123"
set signatureMethod = "HMAC-SHA256"
set version = "1.0"
set token = "acc999token456"
set tokenSecret = "toksec234234"
//sorted array (required !)
set dictionaryArray("oauth_consumer_key") = consumerKey
set dictionaryArray("oauth_nonce") = nonce
set dictionaryArray("oauth_signature_method") = signatureMethod
set dictionaryArray("oauth_timestamp") = timeStamp
set dictionaryArray("oauth_token") = token
set dictionaryArray("oauth_version") = version
//make an encoded (url) param string
set pos = 0
set paramString = ""
set key = ""
for {
set key = $order(dictionaryArray(key),1,value)
quit:(key = "")
set $piece(paramString,"&",$increment(pos)) = key_"="_value
}
set paramStringUtf8 = $zconvert(paramString,"O","UTF8")
set encodedParamString = $zconvert(paramStringUtf8,"O","URL")
// case we have "/" - the uri conversion does not work !
set encodedParamString = $replace(encodedParamString,"/","%2F")
set httpMethod = "GET" // must be uppercase
set url = "https://www.somerandom123.com/noplace/"
set urlUtf8 = $zconvert(url,"O","UTF8")
set encodedUrl = $zconvert(urlUtf8,"O","URL")
// case we have "/" - the uri conversion does not work !
set encodedUrl = $replace(encodedUrl,"/","%2F")
// [payload to sign] = <httpMethod>&<encodedUrl>&<encodedParams>
set baseString = httpMethod _"&"
_ encodedUrl _"&"
_ encodedParamString
//generally need to do the same manipulation as above ...
set cipherKey = customerSecret_"&"_tokenSecret
//SIGN
set HMACSHA256 = $system.Encryption.HMACSHA(256,baseString,cipherKey)
//ENCODE B64
set HMACSHA256Base64 = $system.Encryption.Base64Encode(HMACSHA256)
//ENCODE URL
set HMACSHA256Base64Url = $zconvert(HMACSHA256Base64,"O","URL")
set signature = HMACSHA256Base64Url
//set Authorization header
set authorization = "OAuth "
_"oauth_consumer_key="""_consumerKey_""","
_"oauth_token="""_token_""","
_"oauth_signature_method="""_signatureMethod_""","
_"oauth_timestamp="""_timeStamp_""","
_"oauth_nonce="""_nonce_""","
_"oauth_version="""_version_""","
_"oauth_signature="""_signature_""""
set sc = ..runHttpGET(url,authorization,.out) //your custom method for whatever %Net.HttpRequest you use..
ObjectScriptObjectScript
hope it helped some one to save some time.
Absolutely fantastic and invaluable. Thank you so much.