web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

News and Announcements icon
Community site session details

Community site session details

Session Id :
Power Platform Community / Forums / Power Automate / Content-Type header se...
Power Automate
Answered

Content-Type header seems to be ignored with http action

(0) ShareShare
ReportReport
Posted on by

We're trying to call a REST API hosted in our NetSuite account. NetSuite requires a proprietary Authorization type. We tried providing the Authorization string in the Authentication field but Flow complained about the Type:

 

{ "Authorization":"NLAuth nlauth_account=xxxxxx, nlauth_email=xxxxxxx@xxxxx.com, nlauth_signature=xxxxxxxxxxxxxxx, nlauth_role=xxxx"}


We then tried defining the Authorization header in the main headers field and this worked, however we also need to define the content-type and this appears to be ignored.

 

{ "Authorization":"NLAuth nlauth_account=xxxxxxxxxx, nlauth_email=xxxxxxx@xxxxxxxx.com, nlauth_signature=xxxxxxxxx, nlauth_role=xxxx","Content-Type":"application/json" } 


The NetSuite REST api returns a JSON payload, if we don't explicitly set the Content-Type to "application/json" we get errors. If I temporarily trick the API to return only text, everything works fine which proves the Authorization header is working.

 

What are we doing wrong?

Categories:
I have the same question (0)
  • v-yamao-msft Profile Picture
    Microsoft Employee on at

    Hi Sklett,

     

    This article about Custom APIs can be a reference for you:
    https://powerapps.microsoft.com/en-us/tutorials/register-custom-api/

     

    There is a note in the document stating “Support for API key authentication is coming soon”.

     

    The article also has links for AAD Authentication that may be helpful.

     

    Best regards,
    Mabel Mao

  • Community Power Platform Member Profile Picture
    Microsoft Employee on at

    You're trying exactly the same integration I am planning to do. Keep this thread update, please!

  • Verified answer
    rgmatthes1 Profile Picture
    11 on at

    Old thread, but we had the same problem as you. Unfortunately, the solution isn't pretty. We ended up doing two things:

     

    • Using OAuth instead of NLAuth. Passing account information such as a username and password isn't just insecure, it's fragile. If this user leaves the company, or your service account is decommissioned, stuff starts to break, and it's usually hard to pinpoint where. So we wrote a function app to generate an OAuth header for making calls into NetSuite. You can call the function app from within Logic Apps and have it return the header you need to make your HTTP request to NetSuite. Here's a starting point in PowerShell, but there are other Python examples out there if you Google: https://netsuitehub.com/forums/topic/oauth-powershell-restlet-working-script-example

      This script didn't take us all the way there. I don't think I'm allowed to post my final code, but:
      • You need to sort alphabetically all parameters and encode all values when constructing the signature (including "deploy" and "script"), which this code doesn't do. Powershell "sort" is your friend.
      • This script's nonce generation stinks. You don't want to limit yourself to just a random number, but a random, case-sensitive string. That way you have 62 characters at your disposal instead of 10.
      • Our base URL frustratingly did not start with "rest," but our NS account ID #. None of the NetSuite documentation included this, but we noticed when deploying our script that its external URL was formed differently.
      • Here's a site you can use to check your script-generated signature vs. what NetSuite is looking for: http://lti.tools/oauth/
    • Write our own HTTP request. Again, function apps to the rescue. Instead of using using the built-in Logic Apps step, which as you noted doesn't work well with NetSuite, we made another function app that uses the "Invoke-WebRequest" PowerShell cmdlet to make the web request, then return the result back to Logic Apps. This was just 10 lines of code including comments, so it was far easier than the last bit to write. My only word of advice is to remember that you can submit multiple headers via an HTTP request, which means you need to expand the JSON and go through each one (think "PSObject.Properties") and add the names and values to a hashtable, which you can reference when you get to the "Invoke-WebRequest" step.

    The two steps worked together for us. First we feed the URL and HTTP method (GET, POST, etc.) to the OAuth header generator, then we use the header to form a full HTTP request and via the second function app. This should be scaleable as you tackle more and more autoation with Azure.

  • kevmaitland Profile Picture
    3 on at

    Thanks to @rgmatthes1  - I wouldn't have persisted without your hints.

     

    Updated for REST API (still in beta, so YMMV).

     

    Wall-of-code:

     

    add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
     public bool CheckValidationResult(
     ServicePoint srvPoint, X509Certificate certificate,
     WebRequest request, int certificateProblem) {
     return true;
     }
    }
    "@
    $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
    [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
    
    #--------REST v1.1 - Sharepoint Access, REST_Access_No2FA
    $oauth_consumer_key = "Integration Consumer Key here".ToUpper()
    $oauth_consumer_secret = "Integration Consumer Secret here".ToLower()
    $oauth_token = "Access Token ID here".ToUpper()
    $oauth_token_secret = "Access Token Secret here".ToLower()
    $oauth_signature_method = "HMAC-SHA256"
    $oauth_version = "1.0"
    $realm = "Your Realm" #This is *different* from the URL e.g. 1234567-sb1 becomes 1234567_SB1
    
    
    $HTTP_method = "GET"
    $url = "https://$($realm.ToLower().Replace("_","-")).suitetalk.api.netsuite.com"
    #$query = "/rest/platform/v1/metadata-catalog/record?select=customer"
    $query = "/rest/platform/v1/metadata-catalog/record/customer"
    if($query -match "\?"){
     $parameters = $query.Split("?")[1]
     $query = $query.Split("?")[0]
     }
    else{$parameters = ""}
    
    $oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString()))
    $oauth_timestamp = [int64](([datetime]::UtcNow)-(Get-Date "1970-01-01")).TotalSeconds
    
    
    $oAuthParamsForSigning = @{}
    $oAuthParamsForSigning.Add("oauth_consumer_key",$oauth_consumer_key)
    $oAuthParamsForSigning.Add("oauth_token",$oauth_token)
    $oAuthParamsForSigning.Add("oauth_signature_method",$oauth_signature_method)
    $oAuthParamsForSigning.Add("oauth_version",$oauth_version)
    $oAuthParamsForSigning.Add("oauth_nonce",$oauth_nonce)
    $oAuthParamsForSigning.Add("oauth_timestamp",$oauth_timestamp)
    
    $parameters.Split("&") | % {
     if(![string]::IsNullOrWhiteSpace($_.Split("=")[0])){
     $oAuthParamsForSigning.Add($_.Split("=")[0],$_.Split("=")[1])
     }
     }
    $oAauthParamsString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
     "$_=$($oAuthParamsForSigning[$_])"
     }) -join "&"
    $encodedOAuthParamsString = [uri]::EscapeDataString($oAauthParamsString)
    $encodedUrl = [uri]::EscapeDataString($url+$query)
    
    $base_string = $HTTP_method + "&" + $encodedUrl + "&" + $encodedOAuthParamsString
    $key = $oauth_consumer_secret + "&" + $oauth_token_secret
    $hmacsha265 = new-object System.Security.Cryptography.HMACSHA256
    $hmacsha265.Key = [System.Text.Encoding]::ASCII.GetBytes($key)
    $oauth_signature = [System.Convert]::ToBase64String($hmacsha265.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($base_string)))
    #$oauth_signature - can be compared with PostMan and http://lti.tools/oauth/
    
    $authHeaderString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
     "$_=`"$([uri]::EscapeDataString($oAuthParamsForSigning[$_]))`""
     }) -join ","
    $authHeaderString += ",realm=`"$([uri]::EscapeDataString($realm))`""
    $authHeaderString += ",oauth_signature=`"$([uri]::EscapeDataString($oauth_signature))`""
    
    
    $response = Invoke-RestMethod -Uri $([uri]::EscapeUriString($url+$query)) -Headers @{"Authorization"="OAuth $authHeaderString";"Cache-Control"="no-cache";"Accept"="application/swagger+json";"Accept-Encoding"="gzip, deflate"} -Method $HTTP_method -Verbose -ContentType "application/swagger+json"

     

     

    Broken into functions in a module:

     

    add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
     public bool CheckValidationResult(
     ServicePoint srvPoint, X509Certificate certificate,
     WebRequest request, int certificateProblem) {
     return true;
     }
     }
    "@
    $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
    [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
    
    function get-netsuiteAuthHeaders(){
     [cmdletbinding()]
     Param (
     [parameter(Mandatory = $true)]
     [ValidateSet("GET","POST")]
     [string]$requestType
     
     ,[parameter(Mandatory = $true)]
     [ValidatePattern("http")]
     [string]$url
     
     ,[parameter(Mandatory=$true)]
     [hashtable]$oauthParameters
    
     ,[parameter(Mandatory=$true)]
     [string]$oauth_consumer_secret
    
     ,[parameter(Mandatory=$false)]
     [string]$oauth_token_secret
    
     ,[parameter(Mandatory=$true)]
     [string]$realm
     )
    
     $oauth_signature = get-oauthSignature -requestType $requestType -url $url -oauthParameters $oauthParameters -oauth_consumer_secret $oauth_consumer_secret -oauth_token_secret $oauth_token_secret
    
     $authHeaderString = ($oauthParameters.Keys | Sort-Object | % {
     "$_=`"$([uri]::EscapeDataString($oauthParameters[$_]))`""
     }) -join ","
     $authHeaderString += ",realm=`"$([uri]::EscapeDataString($realm))`""
     $authHeaderString += ",oauth_signature=`"$([uri]::EscapeDataString($oauth_signature))`""
     @{"Authorization"="OAuth $authHeaderString"
     ;"Cache-Control"="no-cache"
     ;"Accept"="application/swagger+json"
     ;"Accept-Encoding"="gzip, deflate"
     }
     }
    
    function get-netsuiteParameters(){
     [cmdletbinding()]
     Param()
     #Don't really store your keys and secrets in plaintext like this - it's just proof-of-concept
     @{oauth_consumer_key = "Integration Consumer Key here".ToUpper()
     ;oauth_consumer_secret = "Integration Consumer Secret here".ToLower()
     ;oauth_token = "Access Token ID here".ToUpper()
     ;oauth_token_secret = "Access Token Secret here".ToLower()
     ;oauth_signature_method = "HMAC-SHA256"
     ;oauth_version = "1.0"
     ;realm = "Your Realm"
     }
     }
    
    function get-oauthSignature(){
     [cmdletbinding()]
     Param (
     [parameter(Mandatory = $true)]
     [ValidateSet("GET","POST")]
     [string]$requestType
     
     ,[parameter(Mandatory = $true)]
     [ValidatePattern("http")]
     [string]$url
     
     ,[parameter(Mandatory=$true)]
     [hashtable]$oauthParameters
    
     ,[parameter(Mandatory=$true)]
     [string]$oauth_consumer_secret
    
     ,[parameter(Mandatory=$false)]
     [string]$oauth_token_secret
     )
     $requestType = $requestType.ToUpper()
     
     $encodedUrl = [uri]::EscapeDataString($url.ToLower())
    
     $oAauthParamsString = (
     $oauthParameters.Keys | Sort-Object | % {
     if(@("realm","oauth_signature") -notcontains $_){
     "$_=$($oauthParameters[$_])"
     }
     }
     ) -join "&"
     $encodedOAuthParamsString = [uri]::EscapeDataString($oAauthParamsString)
    
     $base_string = $requestType + "&" + $encodedUrl + "&" + $encodedOAuthParamsString
     $key = $oauth_consumer_secret + "&" + $oauth_token_secret
    
     Switch($oauthParameters["oauth_signature_method"]){
     "HMAC-SHA1" {
     $cryptoFunction = new-object System.Security.Cryptography.HMACSHA1
     }
     "HMAC-SHA256" {
     $cryptoFunction = new-object System.Security.Cryptography.HMACSHA256
     }
     "HMAC-SHA384" {
     $cryptoFunction = new-object System.Security.Cryptography.HMACSHA384
     }
     "HMAC-SHA512" {
     $cryptoFunction = new-object System.Security.Cryptography.HMACSHA512
     }
     default {
     Write-Error "Unsupported oauth_signature_method [$_]"
     break
     }
     }
    
     $cryptoFunction.Key = [System.Text.Encoding]::ASCII.GetBytes($key)
     $oauth_signature = [System.Convert]::ToBase64String($cryptoFunction.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($base_string)))
     $oauth_signature
     }
    
    function invoke-netsuiteRestMethod(){
     [cmdletbinding()]
     Param(
     [parameter(Mandatory = $true)]
     [ValidateSet("GET","POST")]
     [string]$requestType
     
     ,[parameter(Mandatory = $true)]
     [ValidatePattern("http")]
     [string]$url
    
     ,[parameter(Mandatory=$false)]
     [hashtable]$netsuiteParameters
     )
    
     if(!$netsuiteParameters){$netsuiteParameters = get-netsuiteParameters}
     
     if($url -match "\?"){
     $parameters = $url.Split("?")[1]
     $url = $url.Split("?")[0]
     }
     else{$parameters = ""}
    
     $oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString()))
     $oauth_timestamp = [int64](([datetime]::UtcNow)-(Get-Date "1970-01-01")).TotalSeconds
    
     $oAuthParamsForSigning = @{}
     #Add standard oAuth 1.0 parameters
     $oAuthParamsForSigning.Add("oauth_nonce",$oauth_nonce)
     $oAuthParamsForSigning.Add("oauth_timestamp",$oauth_timestamp)
     $oAuthParamsForSigning.Add("oauth_consumer_key",$netsuiteParameters.oauth_consumer_key)
     $oAuthParamsForSigning.Add("oauth_token",$netsuiteParameters.oauth_token)
     $oAuthParamsForSigning.Add("oauth_signature_method",$netsuiteParameters.oauth_signature_method)
     $oAuthParamsForSigning.Add("oauth_version",$netsuiteParameters.oauth_version)
     #Add parameters from url
     $parameters.Split("&") | % {
     if(![string]::IsNullOrWhiteSpace($_.Split("=")[0])){
     $oAuthParamsForSigning.Add($_.Split("=")[0],$_.Split("=")[1])
     }
     }
     
     $netsuiteRestHeaders = get-netsuiteAuthHeaders -requestType $requestType -url $url -oauthParameters $oAuthParamsForSigning -oauth_consumer_secret $netsuiteParameters["oauth_consumer_secret"] -oauth_token_secret $netsuiteParameters["oauth_token_secret"] -realm $netsuiteParameters["realm"]
     
     $response = Invoke-RestMethod -Uri $([uri]::EscapeUriString($url)) -Headers $netsuiteRestHeaders -Method $requestType -Verbose -ContentType "application/swagger+json"
     $response 
     }

     

     

    Usage:

     

    invoke-netsuiteRestMethod -requestType GET -url "https://YourInstance.suitetalk.api.netsuite.com/rest/platform/v1/metadata-catalog/record/customer"

     

     

  • derekritchison Profile Picture
    2 on at

    Hey all- Very old thread so apologies for resurrecting it, but this has been a useful starting point for my own PowerShell -> NetSuite API HRIS automations. That said, I am only getting the Invalid Login Attempt (401) error. I am using the above "Wall of Code" that was reworked for REST API, which my user/role/token is configured to use. Everything works in my Postman environment, but... not in my local PowerShell script.

    I would be forever grateful if we could dig back into this and see what might be wrong with my code or if something with the REST API has changed in the few years since the above code was working.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Introducing the 2026 Season 1 community Super Users

Congratulations to our 2026 Super Users!

Kudos to our 2025 Community Spotlight Honorees

Congratulations to our 2025 community superstars!

Congratulations to the March Top 10 Community Leaders!

These are the community rock stars!

Leaderboard > Power Automate

#1
Haque Profile Picture

Haque 592

#2
Valantis Profile Picture

Valantis 340

#3
11manish Profile Picture

11manish 284

Last 30 days Overall leaderboard