M2M Client Credential Flow between NetSuite and Synapse

Question:

I am looking to create a flow somewhere in the Azure stack to allow me to get M2M authentication between Azure Synapse and NetSuite. The goal is to be able to drop the use of the ODBC connector and switch to making REST calls for pulling data from NetSuite into Synapse.

I have followed the documentation as best as I can from Oracles Help. The integration record is created, so the only thing I am missing is what needs to happen on the Azure side to get the two systems to authenticate with each other.

I have reviewed this post but this looks like it would be a setup for an API to access Azure resources, where I want Azure Synapse to get the data from NetSuite.

UPDATE: I was able to get M2M to work within NetSuite using Postman by following this video. I am still trying to figure out how to get this created in Azure to allow me to create a JWT to call NetSuite from Synapse.

UPDATE 2: I am now using a spark pool to sign the JWT and when it is run locally I am able to authenticate and get an access token returned.

    import time
    import jwt
    import http.client
    
    sec = '-----BEGIN PRIVATE KEY-----nMIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDkW+cE7G05KETSn#################################################################################n-----END PRIVATE KEY-----'
    jwtheader = {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "rn9dnIL###############"
    }
    iat = round(time.time(),3)
    
    payload_data = {
        "iss": "6477f8bea7f####################",
        "scope": ["restlets", "rest_webservices", "suite_analytics"],
        "aud": "https://#######.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token",
        "exp": iat + 3600,
        "iat": iat
    }
    token = jwt.encode(payload=payload_data,key=sec,headers = jwtheader)
    conn = http.client.HTTPSConnection("#######.suitetalk.api.netsuite.com")
    payload = 'grant_type=client_credentials&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion='+token
    headers = {
      'Content-Type': 'application/x-www-form-urlencoded'
    }
    conn.request("POST", "/services/rest/auth/oauth2/v1/token", payload, headers)
    res = conn.getresponse()
    data = res.read()
    print(data.decode("utf-8"))

However when I use a spark pool in Azure Synapse I am returned with {"error":"invalid_grant"}. With no change in code. I have tried both the requests library as well as the http.client(shown above).

Asked By: mfarinella14

||

Answers:

One of the workaround you can follow for above error,

  • Make sure to use the correct json format in grant type and provided token in similar format as shown in the given doc. which you are following for example

grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=token

  • Before attempting to use the service in your script, make sure it responds well to your credentials.

For more information please refer below links:

Answered By: AjayKumarGhose

I received the same error when copying your template here. But for me it worked once I (1) changed the algorithm in the jwtheader dict to PS256 instead of RS256, and (2) fetched the certificate key without modification using with-open:

with open('<path-to-my-cert-key>/auth-key.pem', 'r') as fh:
    sec = fh.read() # <-- just as it is

jwtheader = {
    "alg": "PS256", # <-- RS256 didn't work for me
    "typ": "JWT",
    "kid": "<my-certificate-id-from-netsuite>"
}

And I can mention that I used this openssl command to generate my certificate, which was the recommended one from Netsuite’s docs:

openssl req -x509 -newkey rsa:4096 -sha256 -keyout auth-key.pem -out auth-cert.pem -nodes -days 730

Hope this works for others as well!

PS. Make sure you download pyjwt and not jwt as I did. It wasn’t the same framework, as time would tell me..

Answered By: JAkerblom

Step 1: Open the file as below OR
copy the file text as it is and store in variable like secret="""private—–key""".

with open('<path-to-my-cert-key>/auth-key.pem', 'r') as fh:
sec = fh.read() # <-- just as it is

Step 2: Remove the alg and typ parameter. Keep only kid.

jwtheader = {
"kid": "<my-certificate-id-from-netsuite>"
}

Step 3: use the below code to create the JWT bearer token.

token = jwt.encode(payload=payload_data, key=sec, algorithm="PS256", headers=jwtheader,)

Please check the documentation for a better understanding.

https://pyjwt.readthedocs.io/en/latest/api.html

Hope this helps. Thanks

Answered By: Ankit Yadav