Skip to content

Sending Authorization Token Bearer through JQuery Ajax – Back end is .NET Core Web Api

I am having a 401 error code when I access to the api using Jquery Ajax. This is my front-end code:

$(document).ready(function() {
      $("#submit").click(function(e) {
        debugger

        let payLoad = JSON.stringify({
          Username: $("#username").val(),
          Password: $("#password").val()
        });
        console.log(payLoad)
        $.ajax({
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          type: "POST",
          url: "https://localhost:44342/api/Authenticate/login",
          data: payLoad,
          dataType: "json",
          success: function(result) {
            console.log('ok')
            debugger
            if (result != "Error") {
              console.log('Authenticated');
              CallAPI(result);
            } else {
              console.log('Invalid username or password');
            }
          },
          error: function(req, status, error) {
            debugger
            alert(error);
          }
        });
      });


      function CallAPI(token) {
        debugger
        $.ajax({
          url: 'https://localhost:44342/api/Customers',
          headers: {
            Authorization: 'Bearer ' + token
          },
          contentType: "application/json",
          dataType: 'json',
          success: function(result) {
            console.log(result)
          },
          error: function(error) {
            console.log(error);
          }
        })
      }

For my back-end, I am using ASP.NET Identity

    [HttpPost]
    [Route("login")]
    public async Task<IActionResult> Login([FromBody] LoginModel model)
    {
        var user = await userManager.FindByNameAsync(model.Username);
        if (user != null && await userManager.CheckPasswordAsync(user, model.Password))
        {
            var userRoles = await userManager.GetRolesAsync(user);

            var authClaims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            };

            foreach (var userRole in userRoles)
            {
                authClaims.Add(new Claim(ClaimTypes.Role, userRole));
            }

            var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));

            var token = new JwtSecurityToken(
                issuer: _configuration["JWT:ValidIssuer"],
                audience: _configuration["JWT:ValidAudience"],
                expires: DateTime.Now.AddHours(3),
                claims: authClaims,
                signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
                );

            return Ok(new
            {
                token = new JwtSecurityTokenHandler().WriteToken(token),
                expiration = token.ValidTo
            });
        }
        return Unauthorized();
    }

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
    private readonly ApplicationContext _context;

    public CustomersController(ApplicationContext context)
    {
        _context = context;
    }

    // GET: api/Customers
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Customer>>> GetCustomer()
    {
        return await _context.Customer.ToListAsync();
    }
}

and my startup.cs code is

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        // For Identity
        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        // Adding Authentication
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })

        // Adding Jwt Bearer
        .AddJwtBearer(options =>
        {
            options.SaveToken = true;
            options.RequireHttpsMetadata = false;
            options.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidAudience = Configuration["JWT:ValidAudience"],
                ValidIssuer = Configuration["JWT:ValidIssuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
            };
        });

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

I have tested. Without [Authorize] attribute, I can see the result response at the client side. But once I have added [Authorize] attribute and added headers property in CallAPI method, it hits 401. I have tested https://localhost:44342/api/Authenticate/login and it works as expected. It returns the token. But when I use the token to call ‘https://localhost:44342/api/Customers’, it hits 401

Answer

But once I have added [Authorize] attribute and added headers property in CallAPI method, it hits 401.

Based on the code of Startup.cs that you shared, we can find that you configured multiple authentication mechanisms in your project.

As we discussed in comments, we can specify the authentication scheme (or schemes) with the [Authorize] attribute they depend on to authenticate the user.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 

For more information about selecting the scheme with the Authorize attribute, please check this doc:

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1#selecting-the-scheme-with-the-authorize-attribute