Article
· Oct 5, 2023 6m read

OAuth 1.0 Authorization sign process

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  HMAC-SHA256 as a signing method. And knowing little to none about it. I started by testing it first in Postman, and all worked just fine. BUT with Object Script, well.. a big smile goes here! :) as I had some issues and no one to suggest..  
In the end the most helpful thing to do was to refer the docs here :  https://oauth.net/core/1.0a/  while the signature method in it is for HMAC-SHA1 and RSA-SHA1 it is valid for HMAC-SHA256 as well.

lets declare some parameters - required to the sign process: (not real values ofc...)

signing method HMAC-SHA256 -
consumer key cons123key321 given by your service provider
consumer  secret conssecret123 given by your service provider
access token acc999token456 given by your service provider
token secret toksec234234 given by your service provider
timestamp 1696497844 format :  $zdatetime($horolog,-2) as seconds from January 1, 1970
nonce s3fr5drk83kde3 random alphaNumeric string
version 1.0 the sign version
url https://www.somerandom123.com/noplace/  
http Method GET for this example. [GET,POST,....], upper case required

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/"

next we need to construct the message to sign: The documentations dictate the following structure :

[payload to sign as string] = <httpMethod>&<encodedUrl>&<encodedParams> 

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
}

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);

 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")

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
----------------------------------------------------------------*/

so I had to forcefully replace "/" to the encoded "%2F" to make sure the result is right. 

set encodedUrlEscape = $replace(encodedUrl,"/","%2F") //required

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

with our message constructed (baseString) we need to construct the key that will sign it.

the structure is:  [key] = <customerSecret>&<tokenSecret>

set cipherKey = customerSecret_"&"_tokenSecret

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

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.. 						

hope it helped some one to save some time.

Discussion (1)2
Log in or sign up to continue