asp.net-web-apicookiesjwtaccess-tokenrefresh-token

If I set AccessToken and RefreshToken both (JWT) as cookies by server, They both automatically will be sent to server in each request from client


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?


Solution

  • 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: