1

I'm trying to send a request to Auth0 from my asp.net core application. I am using HttpClient for that.

Issue is when I create same request in postman everything works fine but if I use it from my .NET Core app than it throws

System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).

Here's the image of postman example:

enter image description here More details about task:

Request type is POST

Successful call would return access_token

POST Request expects few body parametes:

  1. grant_type
  2. client_id
  3. client_secret
  4. audience

and Header content-type must be application/x-www-form-urlencoded.

So the request from postman looks like this:

https://mydemoapplication.auth0.com/oauth/token? grant_type=client_credentials &client_id=some_my_id &client_secret=some_my_client_secrets &audience=https://mydemoapplication.auth0.com/api/v2/

And this works perfectly fine.

But when I try to repeat same action from .NET CORE Web api I get 401 (Unauthorized). all the time.

Here is my C# code:

First we are starting with method RequestTokenFromAuth0

 public async Task<string> RequestTokenFromAuth0(CancellationToken cancellationToken)
 {
            // tokenUrl represents https://mydemoapplication.auth0.com/oauth/token
            var tokenUrl = $"{_auth0HttpConfig.TokenEndpoint}";

            // Creating anonymous object which will be used in post request
            var data = new
            {
                grant_type = "client_credentials",
                client_id =  _auth0HttpConfig.ClientId ,
                client_secret = _auth0HttpConfig.ClientSecret,
                audience = _auth0HttpConfig.Audience
            };

            //var data = $"grant_type=client_credentials&client_id={_auth0HttpConfig.ClientId}&client_secret={_auth0HttpConfig.ClientSecret}&audience={_auth0HttpConfig.Audience}";

            var response = await _auth0Client.PostToken<Auth0Auth>(tokenUrl, data, cancellationToken);
             
            if(response!= null && response.Success && response.Data != null && !string.IsNullOrWhiteSpace(response.Data.Token))
            {
                return response.Data.Token;
            }
            else
            {
                throw new ArgumentException("Token is not retrieved.");
            }
        }


public async Task<T> PostToken<T>(string endpoint, object jsonObject, CancellationToken cancellationToken)
{
    if (string.IsNullOrWhiteSpace(endpoint))
    {
        throw new ArgumentNullException(endpoint);
    }

    var reqMessage = GenerateTokenRequestMessage(HttpMethod.Post, jsonObject, endpoint);

    var result = await GetResult<T>(httpRequestMessage, cancellationToken);

    return result;
}


public HttpRequestMessage GenerateTokenRequestMessage(HttpMethod httpMethod, object objectToPost, string endpoint)
{ 
    var httpRequestMessage = new HttpRequestMessage(httpMethod, endpoint);

    var serializedObjectToCreate = JsonConvert.SerializeObject(objectToPost, new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    });

    httpRequestMessage.Content = new StringContent(serializedObjectToCreate);
    httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

    return httpRequestMessage;
}

private async Task<T> GetResult<T>(HttpRequestMessage request, CancellationToken cancellationToken)
{
    try
    {
        HttpResponseMessage response = await _client.SendAsync(request, cancellationToken);

        response.EnsureSuccessStatusCode(); // THIS LINE Throws exception 401 Unathorized

        var result = await response.Content.ReadAsStringAsync();

        return JsonConvert.DeserializeObject<T>(result);
    }
    catch (Exception ex)
    {
        throw;
    }
}

Something is wrong here and I don't know why I'm getting unathorized, what might be wrong here I'm not sure really! Any kind of help would be great!

P.S Repeating once more again from postman everything works fine!

Thanks

Cheers

Roxy'Pro
  • 4,216
  • 9
  • 40
  • 102
  • It looks like your postman request is passing everything in the url, and your C# code is posting the data in the body. – Lasse V. Karlsen Jul 19 '20 at 21:17
  • @LasseV.Karlsen that's how url is created when I add body values one by one "KEY/VALUE" I will now post image how it looks in postman. – Roxy'Pro Jul 19 '20 at 21:19
  • @LasseV.Karlsen Check for edit, I checked * Body , choosen POST and added values in key/value pairs and with postman everything worked fine... – Roxy'Pro Jul 19 '20 at 21:23
  • @Roxy'Pro the question from @Lasse looks to be key here... in postman you are sending the parameters as `query string` parameters... but in C# code you are sending a JSON object in the body. First, try to make sure to do as done in postman and continue from there. Or try to test sending the data as a JSON object in postman, if that fails, then you may have found the cuase. – Luis Jul 19 '20 at 21:41

2 Answers2

2
_auth0Client.PostToken<Auth0Auth>(tokenUrl, data, cancellationToken);

And PostToken takes data as object jsonObject and passes it to GenerateTokenRequestMessage which then creates the HTTP content:

var serializedObjectToCreate = JsonConvert.SerializeObject(objectToPost, new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore
});

httpRequestMessage.Content = new StringContent(serializedObjectToCreate);
httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

But here you are putting in the data serialized as JSON and expect it to be application/x-www-form-urlencoded. But that’s obviously not the case. What you are generating looks like this:

{"grant_type":"client_credentials","client_id":"ClientId","client_secret":"ClientSecret","audience":"Audience"}

But instead, it should look like this:

grant_type=client_credentials&client_id=ClientId&client_secret=ClientSecret&audience=Audience

You can use the FormUrlEncodedContent type for this:

httpRequestMessage.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
    ["grant_type"] = "client_credentials",
    ["client_id"] = _auth0HttpConfig.ClientId,
    ["client_secret"] = _auth0HttpConfig.ClientSecret,
    ["audience"] = _auth0HttpConfig.Audience,
});
poke
  • 369,085
  • 72
  • 557
  • 602
  • thanks a lot than was solution. P.S Just fix Dictionary syntaax ["grant_type"] = ".." and so on.. thanks a lot man! – Roxy'Pro Jul 19 '20 at 23:08
0

Since you're hitting it from dotnet, I suggest using the Auth0 NuGet package.

  1. Install-Package Auth0.AuthenticationApi
  2. Use this basic code as an outline for your real code to get a token
public class QuestionCode
{
    public async Task<string> GetToken()
    {
        var client = new AuthenticationApiClient("<your_auth0_domain>");
        var tokenRequest = new ClientCredentialsTokenRequest
        {
            ClientId = "<your_client_id>",
            ClientSecret = "<your_client_secret>",
            Audience = "<your_audience>",
        };

        var token = await client.GetTokenAsync(tokenRequest);
        return token.AccessToken;
    }
}

I tested this against a dummy Auth0 API and it worked as expected.

Happy Coding!

jlikens
  • 1
  • 1