I am making a web application using ASP.NET Core using CookieAuthentication
as my MVC authentication and JWT for Web-APIs.
I have configured the cookie authentication and created the JWT token successfully. However I have trouble authorizing my API methods that contain the [Authorization(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
attribute.
Startup.cs
services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "CookieAuthentication";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.ExpireTimeSpan = TimeSpan.FromDays(14);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/Account/Unauthorized";
});
services
.AddAuthentication()
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:JwtIssuer"],
ValidAudience = Configuration["Jwt:JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:JwtSecretKey"]))
};
});
AccountController.cs
[HttpPost]
[Route("Login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromForm]LoginViewModel model)
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
if (model.Username == "test" && model.Password == "test")
{
var name = "Name";
var role = "Admin";
var email = "test123@gmail.com";
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.Email, email),
new Claim(ClaimTypes.Role, role)
};
var credientials = new SigningCredentials(
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_config["Jwt:JwtSecretKey"])),
SecurityAlgorithms.HmacSha256);
var securityToken = new JwtSecurityToken(
issuer: _config["Jwt:JwtIssuer"],
audience: _config["Jwt:JwtIssuer"],
claims: claims,
expires: DateTime.Now.AddMinutes(1),
signingCredentials: credientials
);
HttpContext.Response.Cookies.Append(
"JwtCookie",
"Bearer " + new JwtSecurityTokenHandler().WriteToken(securityToken),
new CookieOptions
{
Expires = DateTime.Now.AddMinutes(1),
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Strict
});
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authenticationProperties = new AuthenticationProperties()
{
ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1),
IsPersistent = true
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authenticationProperties);
#endregion
return Redirect($"{role}/Index");
Private.cshtml
@{
ViewData["Title"] = "Private";
}
<h2>Private Area</h2>
<input type="button" onclick="addUser()" value="Login" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function addUser()
{
$.ajax
({
type: 'POST',
url: '/api/Test/AddUser'
}).done(function (data)
{
console.log("done");
}).fail(function (data, textStatus, xhr)
{
console.log("fail");
})
}
</script>
/api/Test/AddUser method
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpPost]
[Route("AddUser")]
public IActionResult AddUser()
{
var u = new User
{
SamAccountName = "Test",
Role = ""
};
_context.Add(u);
try
{
_context.SaveChanges();
}
catch (Exception e)
{
return BadRequest($"Cannot save: {e}");
}
return Ok();
}
The question I have is:
I am getting 401 error when I try to call the
api/Test/AddUser
method. Is there a way I can send the cookie containing the JWT token through the authorization header automatically, similar to howCookieAuthentication
does it? I know this is because of my not having an Authorization header. However because I stored my JWT token inside the HttpOnly cookie, I cannot find a way to pass the token into the authorization header. I could add Authorization { "Bearer " + token }. I would have to use sessionStorage or use a normal cookie but that would pop up some security concerns. I have seen many tutorials but have never seen how the javascript passes its authorization header, most show passing through authorization header in Postman.If the above could be done, is there a way the expiration date could be synced up with the
CookieAuthentication
cookie? Since a JWT token expiration date cannot be extended like cookie, how would I ensure that the user is able to access the APIs and MVC if they are using two different types of authentication?The project only uses HTTPS and I implemented anti forgery tokens inside the forms I submit. Is there any attacks I should protect against?