Why my authorization JWT is failing when is sent to the Web API?

375 Views Asked by At

Allright, I am struggling with sending my JWT to the Web API and I need help with debugging. I am using Angular 10 client and ASP.NET Core 2.2 for server. My authentication flow looks like this:

To the client there is sent a token generated in server like that:

Claim[] claims = new[] {
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(now).ToUnixTimeSeconds().ToString())
                    // TODO: add additional claims here
                    };

                int tokenExpirationMins = _configuration.GetValue<int>("Auth:JsonWebToken:TokenExpirationInMinutes");
                SymmetricSecurityKey issuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Auth:JsonWebToken:Key"]));

                JwtSecurityToken token = new JwtSecurityToken(
                    issuer: _configuration["Auth:JsonWebToken:Issuer"],
                    audience: _configuration["Auth:JsonWebToken:Audience"], claims: claims, notBefore: now,
                    expires: now.Add(TimeSpan.FromMinutes(tokenExpirationMins)), signingCredentials: new SigningCredentials( issuerSigningKey, SecurityAlgorithms.HmacSha256));
                string encodedToken = new JwtSecurityTokenHandler().WriteToken(token);

                // build & return the response
                TokenResponseViewModel response = new TokenResponseViewModel()
                {
                    Token = encodedToken,
                    Expiration = tokenExpirationMins,
                    Email = user.Email,
                    User = user.UserName
                };
                return Json(response);

And this is fine, the client get all the data from TokenResponseViewModel.

And when the client need to send API request to my api/user/test endpoint, it is not authenticated. Please note, that this is just an enpoint for my trials. And it is secured like this:

/// <summary>
        /// POST: api/user/test
        /// </summary>
        /// <returns>Status code.</returns>
        [HttpGet("Test")]
        [Authorize]
        public IActionResult GetTest()
        {
            return new OkObjectResult(new { Message = "This is secure data!" });
        }

My request looks fine. Below are headers and request data: request

And as the request is not authenticated by the API, it is trying to redirect to http://localhost:50962/Account/Login?ReturnUrl=/api/user/test: enter image description here

And currently I have no idea how to fix this problem. Token seems to be fine, but it is rejected by the Identity framework. JWT is not expires, as the expiration time is set to 100min.

Below is also my Angular request call:

executeCall(): void {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': 'bearer ' + this.auth.getAuth()!.token
      })
    };

    console.log('executing call');
    var url = 'http://localhost:50962/' + 'api/user/test';
    this.http.get<string>(url, httpOptions)
      .subscribe(
        (val) => {
          console.log("POST call successful value returned in body", val);
        },
        response => {
          console.log("POST call in error", response);
          //todo: popup
        },
        () => {
          console.log("The POST observable is now completed.");
          //todo: popup
        });
  }

Startup.cs authentications settings:

services.AddAuthentication(opts =>
            {
                opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(cfg =>
            {
                cfg.RequireHttpsMetadata = false;
                cfg.SaveToken = true;
                cfg.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidIssuer = Configuration["Auth:Jwt:Issuer"],
                    ValidAudience = Configuration["Auth:Jwt:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Auth:Jwt:Key"])),
                    ClockSkew = TimeSpan.Zero,
                    RequireExpirationTime = true,
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = true,
                    ValidateAudience = true
                };
            })

appsettings config:

"JsonWebToken": {
      "Issuer": "http://localhost:50962/",
      "Audience": "http://localhost:50962/",
      "Key": "0pvUGXcvhg1ZRQZGBGy4",
      "TokenExpirationInMinutes": 100
    }
1

There are 1 best solutions below

0
On BEST ANSWER

the problem was with this code, where I had to replace Authorize with Authorize(AuthenticationSchemes = "Bearer"):

/// <summary>
        /// POST: api/user/test
        /// </summary>
        /// <returns>Status code.</returns>
        [HttpGet("Test")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        public IActionResult GetTest()
        {
            return new OkObjectResult(new { Message = "This is secure data!" });
        }

Based on this article.