Forum Discussion
Get OAuth Custom Connector to check for valid token before initiating login flow again
No I'm using authorization code flow: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_158074210415.html
I think I tried client credentials but couldn't get it to work.
Thanks pbiftw92
First of all you should make sure that the flow you're using is enabled in Netsuit admin.
Second, IF you're using Authorization Code Grant Flow, then from the documentation (https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_158081952044.html) we see that the 2nd step POST request has to have the following x-www-form-urlencoded parameters:
- code
- redirect_uri
- grant_type = authorization_code
code_verifier(i think this is not needed)
BUT from your code (also below), I see you're passing:
- code
- redirect_uri
- grant_type = authorization_code
- client_id?
- client_secret?
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
grant_type = "authorization_code",
redirect_uri = redirect_uri,
client_id = client_id,
client_secret = client_secret
],
queryWithCode = Record.AddField(queryString, tokenField, code),
tokenResponse = Web.Contents(token_uri, [
Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
Headers = [
#"Content-type" = "application/x-www-form-urlencoded",
#"Accept" = "application/json"
],
ManualStatusHandling = {400}
]),
body = Json.Document(tokenResponse),
result = if (Record.HasFields(body, {"error", "error_description"})) then
error Error.Record(body[error], body[error_description], body)
else
body
in
result;
Sooo, as I see in the documentation, you should remove client_id and client_secret from the queryString and instead place them in the Headers, in the "Authorization" key clientid:clientsecret Base64 encoded -> quote "The client authentication method used in the header of the request follows the HTTP Basic authentication scheme. For more information, see RFC 7617. The format is clientid:clientsecret. The string value is Base64 encoded. "
They provide an example request:
POST /services/rest/auth/oauth2/v1/token HTTP/1.1
Host: <accountID>.suitetalk.api.netsuite
Authorization: Basic base64blabla (!!! YOU ARE MISSING THIS !!!)
Content-Type: application/x-www-form-urlencoded
code=bla_bla&redirect_uri=bla_bla&grant_type=authorization_code&code_verifier=?!
Something like:
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
grant_type = "authorization_code",
redirect_uri = redirect_uri
],
queryWithCode = Record.AddField(queryString, tokenField, code),
tokenResponse = Web.Contents(token_uri, [
Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
Headers = [
#"Content-type" = "application/x-www-form-urlencoded",
#"Accept" = "application/json",
"Authorization" = "Basic " & Binary.ToText(Binary.FromText(client_id & ":" & client_secret, TextEncoding.Utf8), BinaryEncoding.Base64)
],
ManualStatusHandling = {400}
]),
body = Json.Document(tokenResponse),
result = if (Record.HasFields(body, {"error", "error_description"})) then
error Error.Record(body[error], body[error_description], body)
else
body
in
result;
Please mark this as answer if it helped.
- pbiftw923 years agoFrequent Visitor
This method you suggested works with a slight modification, namely instead of
TokenMethod = (grantType, tokenField, code) => let queryString = [ grant_type = "authorization_code", redirect_uri = redirect_uri ], queryWithCode = Record.AddField(queryString, tokenField, code), tokenResponse = Web.Contents(token_uri, [ Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)), Headers = [ #"Content-type" = "application/x-www-form-urlencoded", #"Accept" = "application/json", "Authorization" = "Basic " & Binary.ToText(Binary.FromText(client_id & ":" & client_secret, TextEncoding.Utf8), BinaryEncoding.Base64) ], ManualStatusHandling = {400} ]), body = Json.Document(tokenResponse), result = if (Record.HasFields(body, {"error", "error_description"})) then error Error.Record(body[error], body[error_description], body) else body in result;I did
TokenMethod = (grantType, tokenField, code) => let queryString = [ grant_type = "authorization_code", redirect_uri = redirect_uri ], queryWithCode = Record.AddField(queryString, tokenField, code), tokenResponse = Web.Contents(token_uri, [ Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)), Headers = [ #"Content-type" = "application/x-www-form-urlencoded", #"Accept" = "application/json", #"Authorization" = "Basic " & Binary.ToText(Text.ToBinary(client_id & ":" & client_secret), BinaryEncoding.Base64) ], ManualStatusHandling = {400} ]), body = Json.Document(tokenResponse), result = if (Record.HasFields(body, {"error", "error_description"})) then error Error.Record(body[error], body[error_description], body) else body in result;This does work in the sense that it returns results, but unfortunately it still has the same issue as the method I was using before where it requires reauthentication every time a query is changed, duplicated or refreshed and doesn't test the current token first before initiating the flow again.
Were you suggesting to combine this change in method with the Extension.CurrentCredential() thing? I can try that next and update if this change makes any difference (e.g. eliminates the errors I was getting previously with Extension.CurrentCredential()).
And yes this is all enabled for my role in the Netsuite UI, otherwise none of these methods would return results at all and would give 404 etc. (I went through that whole journey previously 😀) ...
My general thinking is that the API calls are working fine, but it's actually the M logic that I have implemented that is causing the issue. I borrowed that and repurposed from other OAuth examples I found online, but maybe this Netsuite flow requires specific logic to get it to work. Like for example, I need to add an explicit check/reference to the current token or something...