Looking for someone for a short, one-off job. I h...
# jobs
s
Looking for someone for a short, one-off job. I have seen articles on using an Azure Function App as the signature generator for a NetSuite Oauth1 MS Power App. I got through most of it but still getting an invalid signature when attempting access. If you have experience with this, please contact me.
m
what NetSuite API are you trying to hit?
s
that does not really matter. In the end, I would like to use it for a number of things. But for the purpose of this, I am trying to hit a restlet. <https://#######.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=###&deploy=#>
I was using this as a reference... https://medium.com/@mgr/how-to-connect-to-netsuite-from-microsoft-power-automate-using-oauth-1-0-1d7670972406 ...I think I got the whole thing set up and the function app returns a signature, but no matter how I jiggle the signing string, NetSuite sign in audit trail indicates "InvalidSignature"
m
Gotcha yeah, was just wondering if trying to use RESTlets, SOAP, or REST Web Services. The Oauth signature stuff is a bit different for all three. That blog post is for REST Web Services, not for RESTlets. This reddit post voices your same frustration https://www.reddit.com/r/Netsuite/comments/jjtocs/using_power_automate_with_netsuite/. Looks like there are a few adjustments needed to make your code work with RESTlets
s
holy @Q$%$@#%..... "alphabetically arranged"???? Really????? Thanks. I will try that little piece of idiocy...
m
haha yup. One of the devs at my company lost a few days to that one
s
THANKS MARC! That got me past the authentication string errors. Now I just get a 400 Bad Request...Your browser sent a request that this server could not understand.
d
Did you solve this? DM me your code (without keys obviously :)), I'll take a quick look for you.
s
the azure code for the signing is exactly as in the Medium article above... there is no other real "code" involved. I was getting the invalid login until I followed the changes in the Reddit article. My url is in my original post...
This is what gets signed... GET&https%3A%2F%2F[redacted].restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nldeploy%3D1%26oauth_consumer_key%3D[redacted]%26oauth_nonce%3D68334178%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1612888703%26oauth_token%3D[redacted]%26oauth_version%3D1.0%26script%3D174
this is my connection header... OAuth realm="[redacted]",oauth_consumer_key="[redacted]",oauth_token="[redacted]",oauth_signature_method="HMAC-SHA256",oauth_timestamp="1612888703",oauth_nonce="68334178",oauth_version=”1.0",oauth_signature=”QPc[partially-redacted]wYVIF2s%3D"
m
couple questions as a sanity check: 1. Are you testing this on a netsuite sandbox account, developer account, or production account? 2. Does your RESTlet actually support GET requests? Or do you have it configured to support POSTs only or something?
s
production and the same restlet works absolutely fine in postman
using GET
started this with a known restlet that I have working both in postman and from an excel vb app. once I get the structure working, will create the restlets we need for this interface
d
cracked it after a couple of hours of tinkering. I need to clean the code up a bit first so will post tomorrow ... need to take the dog out for a walk :)
s
Thanks @dynamicl, This is frustrating and anything you have would be a great help.
d
Hey, full working PowerShell script below (for GET or POST). All you need to do is add your params to the top of the script. Assume it works ok for you, it should be easy to follow the steps and see the exact formatting ... and with OAUTH it has to be PERFECT, one char out of place or in a different case with create a different signature which will fail on the NS side. This also uses HMACSHA256. Let me know how you get on 🙂
cls
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
## USER SETTINGS START ##############################################################################################
$restMethod = "GET"
$nsUrlInstanceName = "" #example: 12345-sb1
$nsRealm = "" #example: 12345_SB1
$nsDeployId = "" #example: 1
$nsScriptId = "" #example: 123
$oauth_consumer_key = ""
$oauth_consumer_secret = ""
$oauth_token = ""
$oauth_token_secret = ""
## USER SETTINGS END ##############################################################################################
function EncodeToUpper
{
param($value)
return $value.Replace("%2a","%2A").Replace("%2b","%2B").Replace("%2c","%2C").Replace("%2d","%2D").Replace("%2e","%2E").Replace("%2f","%2F").Replace("%3a","%3A").Replace("%3b","%3B").Replace("%3c","%3C").Replace("%3d","%3D").Replace("%3e","%3E").Replace("%3f","%3F")
}
$oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString()))
$oauth_timestamp = [long](([datetime]::UtcNow)-(Get-Date "1970-01-01")).TotalSeconds
$baseUrl = 'https://'+$nsUrlInstanceName+'.<http://restlets.api.netsuite.com/app/site/hosting/restlet.nl|restlets.api.netsuite.com/app/site/hosting/restlet.nl>'
$fullUrl = 'https://'+$nsUrlInstanceName+'.<http://restlets.api.netsuite.com/app/site/hosting/restlet.nl?script='+$nsScriptId+'&deploy='+$nsDeployId|restlets.api.netsuite.com/app/site/hosting/restlet.nl?script='+$nsScriptId+'&deploy='+$nsDeployId>
$baseUrlEncoded = [System.Web.HttpUtility]::UrlEncode($baseUrl)
$baseUrlEncoded = EncodeToUpper $baseUrlEncoded
#sort param names lexicographically
$params = "deploy=$nsDeployId&oauth_consumer_key=$oauth_consumer_key&oauth_nonce=$oauth_nonce&oauth_signature_method=HMAC-SHA256&oauth_timestamp=$oauth_timestamp&oauth_token=$oauth_token&oauth_version=1.0&script=$nsScriptId"
$paramsEncoded = [System.Web.HttpUtility]::UrlEncode($params)
$paramsEncoded = EncodeToUpper $paramsEncoded
if($restMethod -eq "GET"){
$message = 'GET&'+$baseUrlEncoded+'&'+$paramsEncoded
}
elseif($restMethod -eq "POST"){
$message = 'POST&'+$urlEncoded+'&'+$paramsEncoded
}
else{
"ERROR - Please check REST method parameter"
exit
}
$key = $oauth_consumer_secret + "&" + $oauth_token_secret
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [System.Text.Encoding]::ASCII.GetBytes($key)
$signature = [System.Convert]::ToBase64String($hmac.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($message)))
$signature = [System.Web.HttpUtility]::UrlEncode($signature)
$signature = EncodeToUpper $signature
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")
$headers.Add("Authorization", 'OAuth realm="'+$nsRealm+'", oauth_consumer_key="'+$oauth_consumer_key+'", oauth_token="'+$oauth_token+'", oauth_signature_method="HMAC-SHA256", oauth_timestamp="'+$oauth_timestamp+'", oauth_nonce="'+$oauth_nonce+'", oauth_version="1.0", oauth_signature="'+$signature+'"')
if($restMethod -eq "GET"){
$response = Invoke-RestMethod $fullUrl -Method 'GET' -Headers $headers
$response | ConvertTo-Json
}
elseif($restMethod -eq "POST"){
$body = "{}"
$response = Invoke-RestMethod $url -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
}
s
Am I correct that this is a different approach? Instead of using the function app only for the signing, you are actually having the function app talk to NetSuite and return the data back to the calling service which technically could be not just power automate but any service?
I filled the parms and tried a POST ... got this... 2021-02-10T141022.725 [Error] Executed 'Functions.AllIn' (Failed, Id=73107307-7ea6-48ff-b6a2-f886f2fe0b7d, Duration=3ms)Result: FailureException: No parameter defined in the script or function for the input binding 'Request'.Stack: at Microsoft.Azure.Functions.PowerShellWorker.AzFunctionInfo..ctor(RpcFunctionMetadata metadata) in D\a\1\s\src\FunctionInfo.csline 131at Microsoft.Azure.Functions.PowerShellWorker.FunctionLoader.LoadFunction(FunctionLoadRequest request) in D\a\1\s\src\FunctionLoader.csline 52at Microsoft.Azure.Functions.PowerShellWorker.RequestProcessor.ProcessFunctionLoadRequest(StreamingMessage request) in D\a\1\s\src\RequestProcessor.csline 222
d
Have you tried locally in PowerShell?
s
the above is from the Test/Run option in Code + Test
I tried it from a power automate call as well and had to dump out of it as it was unresponsive and eventually gave me an "Action 'HTTP' failed"
message has been deleted
d
Hey, that code is a full end to end PS script just to run locally for testing. I did it like that so you see every step and the exact format required for OAUTH to work. With that is should be easy to fix your power automate code you had already setup. If I get chance later I'll set it up in Azure.
I just quickly compared your signature to the PS generated signature and you seem to be missing a '&' after ... restlet.nl
GET&https%3A%2F%2F[redacted].restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nl*&*deploy%3D1%26oauth_consumer_key%3D[redacted]%26oauth_nonce%3D68334178%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1612888703%26oauth_token%3D[redacted]%26oauth_version%3D1.0%26script%3D174
Also, you have an extra parameter in your url 'id', for testing I'd remove that for now and just have the restlet return '200' to ensure its getting a response from NS.
s
Thanks. made those changes in my original and got the same result.
...I can get your ps code to work in Azure but when I add a parameter to the GET URL, it fails again. Do additional parameters need to be encoded alphabetically in the signature string?
d
Do you mean adding the extra 'id' param?
s
yeah
d
yeah, add that after the deploy param
deploy=1&id=123&oauth_consumer ....
I added it in these 2 places and works fine for me
message has been deleted
s
YAY!!! that works and I can work with it... Thank you SO much!!!
d
👍