Search code examples
c#asp.net-corehttpclientaccess-tokendotnet-httpclient

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


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


Solution

  • _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,
    });