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:
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
:
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
}
the problem was with this code, where I had to replace
Authorize
withAuthorize(AuthenticationSchemes = "Bearer")
:Based on this article.