最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

oauth 2.0 - Issue with OAuth2.0 Client Credentials Flow with .NET Core Application - Stack Overflow

programmeradmin1浏览0评论

I am trying to integrate a .NET application with NetSuite through RESTlets and REST Web Services. I'm having issues getting an access token back from the POST request in Step 1. I found this GiHtub that has an example for an RSA key. I noticed that the example in GitHub uses 'PS256' as the encoding algorithm for the JWT, which isn't listed as a valid algorithm in the Help Docs:
Help Docs
So I've tried converting it to ES256. I used the following openssl command to generate the certificate:
openssl req -new -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 365 -out public.pem -keyout private.pem

I used openssl that came pre-installed with Git Bash. I created the integration record and Client Credentials Setup.
Integration

Issue with Client Credentials Flow in .NET Core Application Here is the code for my .NET project (ASP.NET Core Web App (Model-View-Controller)) :

Controller Function:

    public async Task<JsonResult> GenJWT()
    {

        NetSuiteIntegration ES = new NetSuiteIntegration()
        {
            AccountId = "ACCOUNT_ID",
            ConsumerKey = "CONSUMER_KEY",
            ClientCredentialsCertificateId = "CLIENT_CREDENTIALS_ID",
            PrivateKeyPem = "PRIVATE_KEY_CONTENT"
        };

        AccessTokenHandler main = new AccessTokenHandler(ES);

        var accessToken = await main.GetAccessToken();

        return new JsonResult(new { accessToken = accessToken });
    }

AccessTokenHandler:

public class NetSuiteIntegration
{
    public string AccountId { get; set; }
    public string ConsumerKey { get; set; }
    public string PrivateKeyPem { get; set; }
    public string ClientCredentialsCertificateId { get; set; }
}

public class AccessTokenHandler
{
    private readonly NetSuiteIntegration netSuiteCredentials;
    private readonly string tokenEndPointUrl;
    private readonly HttpClient _httpClient = new HttpClient();

    public AccessTokenHandler(NetSuiteIntegration netSuiteCredentials)
    {
        thisSuiteCredentials = netSuiteCredentials;
        tokenEndPointUrl = $"https://{thisSuiteCredentials.AccountId}.suitetalk.apisuite/services/rest/auth/oauth2/v1/token";
    }

    public string GetJwtToken()
    {

        ECDsa ecdsa = ECDsa.Create();

        var privateKeyAsString = thisSuiteCredentials.PrivateKeyPem;
        byte[] bytes = Convert.FromBase64String(privateKeyAsString);

        ecdsa.ImportPkcs8PrivateKey(bytes, out _);

        var ECDsaSecurityKey = new ECDsaSecurityKey(ecdsa);
        ECDsaSecurityKey.KeyId = netSuiteCredentials.ClientCredentialsCertificateId;

        var now = DateTime.UtcNow;

        var tokenHandler = new JwtSecurityTokenHandler();
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            IncludeKeyIdInHeader = true,
            TokenType = "JWT",
            Issuer = netSuiteCredentials.ConsumerKey,
            Audience = tokenEndPointUrl,
            Expires = now.AddMinutes(60),
            IssuedAt = now,
            Claims = new Dictionary<string, object> { { "scope", new[] { "restlets", "rest_webservices" } } },
            SigningCredentials = new SigningCredentials(ECDsaSecurityKey, SecurityAlgorithms.EcdsaSha256)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);

        return tokenHandler.WriteToken(token);

    }
    public async Task<string> GetAccessToken()
    {
        string clientAssertion = GetJwtToken();

        Debug.WriteLine("clientAssertion: " + clientAssertion);

        var requestParams = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("grant_type", "client_credentials"),
            new KeyValuePair<string, string>("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
            new KeyValuePair<string, string>("client_assertion", clientAssertion)
        };

        using var httpRequest = new HttpRequestMessage(HttpMethod.Post, tokenEndPointUrl);
        httpRequest.Content = new FormUrlEncodedContent(requestParams);

        var httpResponse = await _httpClient.SendAsync(httpRequest);
        var responseJson = await httpResponse.Content.ReadAsStringAsync();

        return responseJson;
    }

NOTE: With the private key, I just have the baes64 string value, no header/footer and new lines ("------ BEGIN PRIVATE KEY-----").

Whenever I try to get an access token, I get the 'invalid_grant' error.

I feel like I've tried every combo of with/without header for all the ECDsa Import Key Functions and this was the only one that didn't error out. I tried with an RSA key and still had the same issues

I've been on this issue for a while now and it feels like I'm just going in circles. Any and all help would be greatly appreciated. I think I posted everything relevant but if not I will happily add any more info.

发布评论

评论列表(0)

  1. 暂无评论