Created
April 22, 2025 18:24
-
-
Save jbyte2009/52c04240d25afa0699c14180c29475fb to your computer and use it in GitHub Desktop.
How to use NetSuite REST API with OAuth 2 and C# .NET - New Authorization for April 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| NetSuite Machine to Machine (M2M) Authentication to authenticate and retrieve an access token. | |
| Visual Studio 2022 | |
| Application: Class Library | |
| .NET Core 6 - C# | |
| Package: Portable.BouncyCastle | |
| ========================================= | |
| using Microsoft.IdentityModel.Tokens; | |
| using NetSuiteProcessor6.Common.Init; | |
| using NetSuiteProcessor6.Common.Model; | |
| using NetSuiteProcessor6.Model; | |
| using Org.BouncyCastle.Crypto.Parameters; | |
| using Org.BouncyCastle.OpenSsl; | |
| using Org.BouncyCastle.Security; | |
| using System.Collections.Generic; | |
| using System; | |
| using System.IdentityModel.Tokens.Jwt; | |
| using System.IO; | |
| using System.Security.Cryptography; | |
| using System.Text.Json; | |
| using System.Threading.Tasks; | |
| #nullable disable | |
| namespace NetSuiteProcessor6.Common.OAuth | |
| { | |
| public class NetSuiteApiClient | |
| { | |
| private static string RestApiRoot; | |
| private static string Oauth2ApiRoot; | |
| private static string RecordApiRoot; | |
| private static string TokenEndPointUrl; | |
| private static HttpClient _httpClient; | |
| private static RSACryptoServiceProvider provider; | |
| private static RsaSecurityKey rsaSecurityKey; | |
| private static SigningCredentials signingCreds; | |
| private static PemReader pemRdr; | |
| private static RSAParameters rsaParams; | |
| private static byte[] privateKeyRaw; | |
| private static NsToken response; | |
| private static string responseJson; | |
| private static AuthCred AuthCred; | |
| #region Method | GetAccessToken | | |
| public static async Task<string> GetAccessToken(AuthCred inCred) | |
| { | |
| Init(inCred); | |
| var url = string.Format("{0}/token/", Oauth2ApiRoot); | |
| var clientAssertion = GetJwtToken(); | |
| var requestParams = new List<KeyValuePair<string, string>> | |
| { | |
| new("grant_type", "client_credentials"), | |
| new("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"), | |
| new("client_assertion", clientAssertion) | |
| }; | |
| var httpRequest = new HttpRequestMessage(HttpMethod.Post, url) | |
| { | |
| Content = new FormUrlEncodedContent(requestParams) | |
| }; | |
| using (_httpClient = new HttpClient()) | |
| { | |
| var httpResponse = await _httpClient.SendAsync(httpRequest); | |
| responseJson = await httpResponse.Content.ReadAsStringAsync(); | |
| } | |
| response = JsonSerializer.Deserialize<NsToken>(responseJson); | |
| return response.access_token; | |
| } | |
| #endregion | |
| #region Method | GetJWTToken | | |
| public static string GetJToken(AuthCred inCred) | |
| { | |
| Init(inCred); | |
| var tkn = GetJwtToken(); | |
| return tkn; | |
| } | |
| #endregion | |
| #region Method | Init | | |
| private static void Init(AuthCred inCred) | |
| { | |
| AuthCred = inCred; | |
| RestApiRoot = string.Format(sInit.RestApiRoot, inCred.AccountID); | |
| Oauth2ApiRoot = string.Format(sInit.Oauth2ApiRoot, RestApiRoot); | |
| RecordApiRoot = string.Format(sInit.RecordApiRoot, RestApiRoot); | |
| TokenEndPointUrl = string.Format(sInit.TokenEndPointUrl, Oauth2ApiRoot); | |
| } | |
| #endregion | |
| #region Method | GetJwtToken | | |
| private static string GetJwtToken() | |
| { | |
| pemRdr = new PemReader(new StringReader(AuthCred.PrivateKeyPem)); | |
| rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)pemRdr.ReadObject()); | |
| var provider = RSA.Create(4096); | |
| provider.ImportParameters(rsaParams); | |
| rsaSecurityKey = new RsaSecurityKey(provider); | |
| // Create signature and add to it the certificate ID provided by NetSuite. | |
| signingCreds = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSsaPssSha256); | |
| signingCreds.Key.KeyId = AuthCred.ClientCredentialsCertificateId; | |
| // Get issuing timestamp. | |
| var now = DateTime.UtcNow; | |
| // Create token. | |
| var tokenHandler = new JwtSecurityTokenHandler(); | |
| var tokenDescriptor = new SecurityTokenDescriptor | |
| { | |
| Issuer = AuthCred.ApiConsumerKey, | |
| Audience = TokenEndPointUrl, | |
| Expires = now.AddMinutes(5), | |
| IssuedAt = now, | |
| Claims = new Dictionary<string, object> { | |
| { "scope", new[] { "rest_webservices", "restlets" } } | |
| }, | |
| SigningCredentials = signingCreds | |
| }; | |
| var token = tokenHandler.CreateToken(tokenDescriptor); | |
| var tokenText = tokenHandler.WriteToken(token); | |
| return tokenText; | |
| } | |
| #endregion | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Some variables that I store in a Resource file:
RestApiRoot = https://[account id].suitetalk.api.netsuite.com/services/rest
Oauth2ApiRoot = https://[account id].suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1
TokenEndPointUrl = https://[account id].suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token