Consuming web api with JWT authentication console app

Heinz Deubler 181 Reputation points
2023-01-02T18:20:27.29+00:00

I have a console app that I copied from this forum that is supposed to consumes a web api that I wrote. The api works fine with postman and swagger.
I set a breakpoint after "var response = await httpClient.PostAsJsonAsync(@"/Auth/Login", user);" where I am getting a response 200 (see image below) but no token.

![275502-img.png][1]

// Console app souce code:

using System;  
using System.Diagnostics;  
using System.Linq;  
using System.Net.Http;  
using System.Net.Http.Headers;  
using System.Net.Http.Json;  
using System.Security.Cryptography.X509Certificates;  
using System.Threading.Tasks;  
  
  
  
internal class Program  
{  
    private static HttpClient httpClient = new HttpClient();  
    private static async Task Main(string[] args)  
    {  
          
        httpClient.BaseAddress = new Uri("https://localhost:7040");  
        httpClient.DefaultRequestHeaders.Clear();  
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
          
  
        User user = new User() { Password = "readonly@user.com", Username = "readonly@user.com" };  
        try  
        {  
            //Get the JWT  
            string token = await AuthenticateAsync(user);  
            Debug.WriteLine("Token = " + token);  
         
  
          
  
        //Call a secured endpoint  
        var message = await Secured(token);  
        Console.WriteLine($"Response: {message}");  
        }  
        catch (Exception ex)  
        {  
            Debug.WriteLine(ex.Message);  
            Console.Read();  
        }  
  
    }  
  
    private static async Task<string> AuthenticateAsync(User user)  
    {  
        var response = await httpClient.PostAsJsonAsync(@"/Auth/Login", user);  
        Debug.WriteLine("response = ", response);  
        TokenResponse token = await response.Content.ReadFromJsonAsync<TokenResponse>();  
          
        return token.Token;  
    }  
  
    private static async Task<string> Secured(string token)  
    {  
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);  
        string response = await httpClient.GetStringAsync(@"secret2");  
        return response;  
    }  
}  
  
  
public class User  
{  
    public string Username { get; set; } = string.Empty;     
    public string Password { get; set; } = string.Empty;      
}  
  
public class TokenResponse  
{  
    public string Token { get; set; } = string.Empty;  
}  

// login AuthController
[HttpPost]
[Route("login")]

    public async Task<IActionResult> LoginAsync(Models.DTO.LoginRequest loginRequest)  
    {  
        var user = await userRepository.AuthenticateAsync(loginRequest.Username, loginRequest.Password);  

        if(user != null)  
        {  
            var token = await tokenHandler.CreateTokenAsync(user);  

            return Ok(token);  
        }  

        return BadRequest("Username or Password are incorrect");  
    }  
ASP.NET API
ASP.NET API
ASP.NET: A set of technologies in the .NET Framework for building web applications and XML web services.API: A software intermediary that allows two applications to interact with each other.
294 questions
{count} votes

3 answers

Sort by: Most helpful
  1. Arharbi, Adnane 136 Reputation points
    2023-01-02T18:31:11.67+00:00

    Hi,
    Here are a few things you might want to consider:

    1. Make sure that the URL you are using for the HTTP requests is correct and that the server is running.
    2. Check the server's logs for any errors that might be occurring during the request.
    3. If you are getting an error when calling PostAsJsonAsync, you can add a check to see what the status code of the response is. If it's not
      a success status code (e.g. 200), you can throw an exception with the status code and message to help debug the issue.
    4. You might also want to add some additional error handling and logging in the Secured method to help track down the issue.
    5. Make sure that the userRepository.AuthenticateAsync method is returning the expected user. You can add some logging or a debugger
      breakpoint to check the value of user after it is returned from the repository.
    6. If the user is not null, check the value of token after it is returned from the tokenHandler.CreateTokenAsync method. Make sure it is not
      null and that it has the expected structure.
    7. If the CreateTokenAsync method is returning a null or invalid token, you may want to add some additional error handling and logging
      to the CreateTokenAsync method to help debug the issue.
    8. If the user is null, you may want to add some logging or a debugger breakpoint to the BadRequest branch to see if it is being reached
      and why. This could be due to an issue with the AuthenticateAsync method, or it could be due to incorrect login credentials being
      provided.

    I hope this helps! Let me know if you have any other questions.

    0 comments No comments

  2. Heinz Deubler 181 Reputation points
    2023-01-02T21:21:04.647+00:00

    Sorry ArharbiAdnane-7070 but your response didn't help. As you can see from the image, the response is Ok200.

    I verified that on the API side the token is created at line 7 "var token = await tokenHandler.CreateTokenAsync(user);" but unfortunately it doesn't arrive at console applicate at line 47 "var response = await httpClient.PostAsJsonAsync(@"/Auth/Login", user);"


  3. AgaveJoe 26,201 Reputation points
    2023-01-04T17:08:18.613+00:00

    But this still doesn't solve my original problem. The token is returned to the console app but the console app never receives it.

    The original code that you copied works perfectly. Unfortunately you did not post all the relevant code so the community can only guess what mistakes are in your code base. Please make an effort to debug your code or provide enough code to reproduce this issue if you need community debugging support.

    Minimal Web API

    using Microsoft.AspNetCore.Authorization;  
    using Microsoft.IdentityModel.Tokens;  
    using System.IdentityModel.Tokens.Jwt;  
    using System.Security.Claims;  
    using System.Text;  
      
    var builder = WebApplication.CreateBuilder(args);  
      
    builder.Services.AddAuthorization();  
    builder.Services.AddAuthentication().AddJwtBearer(options =>  
    {  
        options.TokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuer = false,  
            ValidateAudience = false,  
            ValidateLifetime = true,  
            ValidateIssuerSigningKey = true,  
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"))  
        };  
    });  
      
    // Add services to the container.  
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle  
    builder.Services.AddEndpointsApiExplorer();  
    builder.Services.AddSwaggerGen();  
      
    var app = builder.Build();  
      
    // Configure the HTTP request pipeline.  
    if (app.Environment.IsDevelopment())  
    {  
        app.UseSwagger();  
        app.UseSwaggerUI();  
    }  
      
    app.MapGet("/api/test", [AllowAnonymous] () => "Hello you!");  
      
    app.MapGet("/secret2", [Authorize] () => $"Hello You. This is a secret!!!");  
      
    app.MapPost("/security/createToken",  
        [AllowAnonymous] (User user) =>  
        {  
            if (user.UserName == "user" && user.Password == "123")  
            {  
                var claims = new[]  
            {  
                                 new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),  
                                 new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),  
                                 new Claim(JwtRegisteredClaimNames.GivenName, user.UserName),  
                                 new Claim(JwtRegisteredClaimNames.Email, "user@test.com"),  
                                 new Claim(ClaimTypes.Role, "Administrator"),  
                                 new Claim("Role1", "Administrator"),  
                                 new Claim("Role2", "Standard"),  
                                 new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())  
                };  
      
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"));  
                var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);  
      
                var tokeOptions = new JwtSecurityToken(  
                    issuer: "https://localhost:7217",  
                    audience: "https://localhost:7217",  
                    claims: claims,  
                    expires: DateTime.Now.AddMinutes(50),  
                    signingCredentials: signinCredentials  
                );  
                var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);  
                TokenResponse response = new TokenResponse() { Token = tokenString };  
                return Results.Ok(response);  
            }  
            return Results.Unauthorized();  
        });  
      
    app.UseHttpsRedirection();  
    app.Run();  
      
      
    public class User  
    {  
        public string UserName { get; set; } = "";  
        public string Email { get; set; } = "";  
        public string Password { get; set; } = "";  
        public string AddInfo { get; set; } = "";  
    }  
      
    public class TokenResponse  
    {  
        public string Token { get; set; } = string.Empty;  
    }  
    

    Console App

    // See https://aka.ms/new-console-template for more information  
    using System;  
    using System.Diagnostics;  
    using System.Linq;  
    using System.Net.Http;  
    using System.Net.Http.Headers;  
    using System.Net.Http.Json;  
    using System.Security.Cryptography.X509Certificates;  
      
    //Console.WriteLine("Hello, World!");  
      
    internal class Program  
    {  
        private static HttpClient httpClient = new HttpClient();  
        private static async Task Main(string[] args)  
        {     
            httpClient.BaseAddress = new Uri("https://localhost:7217");  
            httpClient.DefaultRequestHeaders.Clear();  
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
      
            User user = new User() { AddInfo = "info", Email = "user@email.com", Password = "123", UserName = "user" };  
      
            //Get the JWT  
            string token = await AuthenticateAsync(user);  
            Console.WriteLine(token);  
            Debug.WriteLine("Token = " + token);  
      
            Console.WriteLine();  
      
            //Call a secured endpoint  
            var message = await Secured(token);  
            Console.WriteLine($"Response: {message}");  
      
        }  
      
        private static async Task<string> AuthenticateAsync(User user)  
        {  
            var response = await httpClient.PostAsJsonAsync(@"security/createToken", user);  
            TokenResponse token = await response.Content.ReadFromJsonAsync<TokenResponse>();  
            return token.Token;  
        }  
      
        private static async Task<string> Secured(string token)  
        {  
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);  
            string response = await httpClient.GetStringAsync(@"secret2");  
            return response;  
        }  
    }  
      
      
    public class User  
    {  
        public string UserName { get; set; } = string.Empty;  
        public string Email { get; set; } = string.Empty;  
        public string Password { get; set; } = string.Empty;  
        public string AddInfo { get; set; } = string.Empty;  
    }  
      
    public class TokenResponse  
    {  
        public string Token { get; set; } = string.Empty;  
    }  
    

    276118-capture.png

    0 comments No comments