In every login request I set AccessToken and RefreshToken both as Cookies in ASP.NET Core 8 WebApi Controller:
[HttpHead("Auth/Login")]
public async Task<IResult> Login([FromHeader] long phoneNumber)
{
AuthTokenDTO result = await _dBContext.User.Login(phoneNumber);
if (result is null)
return Results.BadRequest();
HttpContext.Response.Cookies.Append(
"AccessToken",
result.Token,
new CookieOptions
{
Expires = DateTime.Now.AddMinutes(
int.Parse(_configuration["JWT:TknValidityInMunutes"])
),
SameSite = SameSiteMode.Lax,
HttpOnly = true,
Path = "/",
Domain = ".localhost",
}
);
HttpContext.Response.Cookies.Append(
"RefreshToken",
result.RefreshToken,
new CookieOptions
{
Expires = DateTime.Now.AddMinutes(
int.Parse(_configuration["JWT:RefTknValidityInHours"])
),
SameSite = SameSiteMode.Lax,
HttpOnly = true,
Path = "/",
Domain = ".localhost",
}
);
return Results.Ok();
}
My Program.cs file:
builder.Services.AddCors(options =>
{
options.AddPolicy(
name: MyAllowSpecificOrigins,
policy =>
{
policy
.WithOrigins(["http://localhost:5173", "http://localhost:5247"])
.AllowAnyHeader()
.AllowCredentials()
.AllowAnyMethod();
}
);
});
ConfigurationManager config = builder.Configuration;
builder.Services.AddHttpLogging(o => { });
builder
.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = config["JWT:Issuer"],
ValidAudience = config["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JWT:Key"])),
ValidateIssuer = true,
ClockSkew = new TimeSpan(0),
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["RefreshToken"];
return Task.CompletedTask;
}
};
});
builder.Services.AddAuthorization(options =>
options.AddPolicy("IsAdmin", p => p.RequireClaim("IsAdmin", "True"))
);
Front is SvelteKit with FetchAPI:
promiseFunc: fetch('http://localhost:5247/Api/User/Auth/Login', {
method: 'HEAD',
credentials: 'include',
headers: { phoneNumber }
}),
I need AccessToken cookie to be sent to the server in each request by client automatically, It works and that's ok, But the RefreshToken will being sent too in each request and as I know RefreshToken must not be sent in each request for security reasons, how can I handle this? do I have to not set RefreshToken in cookie and set it to localStorage and send it everytime i need by hand?
I would keep both tokens in cookies to reduce token threats in the browser. Just give the refresh cookie a path like /refresh
where that is a path that you use to rewrite cookies with new tokens.
I tend to use cookie settings like these:
new CookieOptions
{
SameSite = SameSiteMode.Strict,
HttpOnly = true,
Path = "/refresh",
}
Where:
SameSite=strict
prevents other sites from sending the cookieDomain
means the cookie can't be sent my other originsExpires
makes it a session cookie that is removed when the user closes all browser windows