Search code examples
c#asp.net-web-apidotnet-httpclient

How to Post into a third party URL and get access token


In my ASP.NET Core-6 Web API, I have a challenge. I have a 3rd party URL as given below:

URL: http://api.thirdpartycompany.com:2233/api/oauth/login

Request:
{
 "username": to_be_shared,
 "password": to_be_shared
 
}
Response:
‘{
 "response_code": "00",
 "response_description": "Success"
 "data": {...},
 "size": 0,
 "access_token": "access_token",
 "refresh_token": "refresh_token",
 "expires_in": "18000000",
 "token_type": "BEARER"
}’

Sample Access Token Request Call:

url = "http://api.thirdpartycompany.com:2233/api/oauth/login"
payload = '{
 "username": to_be_shared,
 "password": to_be_shared
 
}'
headers = {
 'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = payload)

I am to POST into that given url of the third party and get their response, including the access token.

So far, I have done this:

DTO:

public class OAuthLoginRequest
{
    public string username { get; set; }
    public string password { get; set; }

}

public class OAuthLoginResponse
{
    public string response_code { get; set; }
    public string response_description { get; set; }
    public int size { get; set; }
    public string access_token { get; set; }
    public string refresh_token { get; set; }
    public string expires_in { get; set; }
    public string token_type { get; set; }
}

So far, this is what I have:

public class GenericResponseDto<T>
{
    public string response_code { get; set; }
    public string response_description { get; set; }
}

public interface IAuthService
{
    Task<GenericResponseDto<object>> LoginUser(OAuthLoginRequest request);
}


public class AuthService : IAuthService
{
    public async Task<GenericResponseDto<object>> LoginUser(OAuthLoginRequest request)
    {
        var response = new GenericResponseDto<object>();

        return response;
    }
}

DIServiceExtension:

public static class DIServiceExtension
{   
    public static void AddDependencyInjection(this IServiceCollection services)
    {
        // Add Service Injections Here -- Auth
        services.AddScoped<IAuthService, AuthService>();
    }
}

Program.cs

builder.Services.AddDependencyInjection();

Using HttpClient, How do I complete AuthService and when user enters the required username and password, submits the request then it gets the response including access token from the third party URL (http://api.thirdpartycompany.com:2233/api/oauth/login) as response?

How do I achieve this?


Solution

  • FWIW please use either JsonPropertyNameAttribute or JsonProperty depending on what serialization/ deserialization library you're using and keep the names of the properties in your C# classes C#-like (i.e PascalCase, not snake_case)
    The answer is written assuming you did that, so I'll use the ResponseCode property instead of response_code


    Now to the actual answer.

    This is relatively simple, you just need to post your data to the third part API, read the result and return it up the call stack. Like so

    public class AuthService : IAuthService
    {
        // Configure your HttpClient injection as described here:
        // https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
        private readonly HttpClient _httpClient;
    
        public AuthService(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
    
        public async Task<OAuthLoginResponse> LoginUser(OAuthLoginRequest request)
        {
            var postContent = new StringContent(
                JsonSerializer.Serialize(request),
                Encoding.UTF8,
                "application/json"
            );
    
            var response = await _httpClient.PostAsync("oauth/login", postContent);
            if (!response.IsSuccessStatusCode)
                throw new Exception("Third party API request failed");
    
            await using var stream = await response.Content.ReadAsStreamAsync();
            return JsonSerializer.DeserializeAsync<OAuthLoginResponse>(stream);
        }
    }
    

    Instead of returning a OAuthLoginResponse directly, you could change your GenericResponseDto first of to something specific like OAuthResponseDto and secondly to have the fields you need, like

    public class OAuthResponseDto
    {
        [JsonPropertyName("response_code")]
        public string ResponseCode { get; set; }
    
        [JsonPropertyName("response_description")]
        public string ResponseDescription { get; set; }
    
        // More properties, like AccessToken, RefreshToken, ExpiresIn...
    }
    

    And then replace the last two lines of the LoginUser with this:

    await using var stream = await response.Content.ReadAsStreamAsync();
    var response = JsonSerializer.DeserializeAsync<OAuthLoginResponse>(stream);
    
    return new OAuthResponseDto
    {
        ResponseCode = response.ResponseCode,
        ResponseDescription = response.ResponseDescription,
        // rest of the mapping
    };
    

    Small aside, this is how you'd configure your HttpClient injection

    services.AddHttpClient<IAuthService, AuthService>(client =>
    {
        client.BaseAddress = new Uri("http://api.thirdpartycompany.com:2233/api");
    });
    

    Note: I intentionally left out quite a bit of error checking to make this answer short and sweet, but it's still quite a long answer, you'll have to add that error checking in your implementation.

    Note 2: I also don't 100% guarantee that all of this compiles first go, I did my best, but I wrote a large part of this in the Stack Overflow editor, there may be a missing parenthesis or comma or semicolon somewhere, trivial fixes