Let me give you some context.
I am currently trying to implement a Refresh/Access token setup for my authentication and authorization. I think I understand the idea and the purpose of each token. But the issue comes with I am not sure about how to proceed with the implementation.
Before what I would do was just have the Access Token be stored through localStorage in the frontend. And then attached to the relevant API calls through the Authentication header.
And it did worked. But lately I've been trying to implement it a different way. This time I want both the Access and Refresh token be HTTP-Only tokens.
Now this complicated things a bit. As I believe or I feel like ASP.NET Core is wired so the default token is the Bearer one.
Meaning for the HTTP-Only to serve its purpose I had to setup the token manually through the JWT's events. Like so:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidateLifetime = true,
ValidIssuer = config["JWT:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JWT:Key"]!)),
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = ctx =>
{
ctx.Request.Cookies.TryGetValue("access-token", out var accessToken);
if (!string.IsNullOrEmpty(accessToken))
{
ctx.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
The idea is to have a HTTP-Only be used as the Bearer on ASP.NET Core. So I can use the [Authorize] attribute on the endpoints as well as the rest of the functionality that this brings.
But it is not working.
I've done some testing and the token is correctly generated and also correctly grabbed from the HttpContext.
I've created a validate method in a Token Service class in order to test if my Token is correctly generated. And it is.
This is the method I used to check my tokens.
public ClaimsPrincipal? ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidateLifetime = true,
ValidIssuer = _config["JWT:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:Key"]!)),
};
try
{
return tokenHandler.ValidateToken(token, validationParameters, out var result);
}
catch (SecurityTokenException)
{
return null;
}
}
Now I think the issue comes from the fact I don't yet understand fully how [Authorize] works and I believe the is still something more to do in order to make it work.
Any feedback, guidance or advice into how to solve this issue would be appreciated!
Thank you for your time!
Let me give you some context.
I am currently trying to implement a Refresh/Access token setup for my authentication and authorization. I think I understand the idea and the purpose of each token. But the issue comes with I am not sure about how to proceed with the implementation.
Before what I would do was just have the Access Token be stored through localStorage in the frontend. And then attached to the relevant API calls through the Authentication header.
And it did worked. But lately I've been trying to implement it a different way. This time I want both the Access and Refresh token be HTTP-Only tokens.
Now this complicated things a bit. As I believe or I feel like ASP.NET Core is wired so the default token is the Bearer one.
Meaning for the HTTP-Only to serve its purpose I had to setup the token manually through the JWT's events. Like so:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidateLifetime = true,
ValidIssuer = config["JWT:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JWT:Key"]!)),
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = ctx =>
{
ctx.Request.Cookies.TryGetValue("access-token", out var accessToken);
if (!string.IsNullOrEmpty(accessToken))
{
ctx.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
The idea is to have a HTTP-Only be used as the Bearer on ASP.NET Core. So I can use the [Authorize] attribute on the endpoints as well as the rest of the functionality that this brings.
But it is not working.
I've done some testing and the token is correctly generated and also correctly grabbed from the HttpContext.
I've created a validate method in a Token Service class in order to test if my Token is correctly generated. And it is.
This is the method I used to check my tokens.
public ClaimsPrincipal? ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidateLifetime = true,
ValidIssuer = _config["JWT:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:Key"]!)),
};
try
{
return tokenHandler.ValidateToken(token, validationParameters, out var result);
}
catch (SecurityTokenException)
{
return null;
}
}
Now I think the issue comes from the fact I don't yet understand fully how [Authorize] works and I believe the is still something more to do in order to make it work.
Any feedback, guidance or advice into how to solve this issue would be appreciated!
Thank you for your time!
Share Improve this question edited Mar 30 at 10:08 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Mar 30 at 8:38 yzkaelyzkael 3312 silver badges9 bronze badges1 Answer
Reset to default 1First, ensure UseAuthentication
is called before UseAuthorization
in Startup.cs
/Program.cs
:
app.UseAuthentication();
app.UseAuthorization();
Then, when use the [Authorize]
attribute, try to specify the JWT Bearer Scheme:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Besides, when setting the access token cookie, include necessary attributes, to make sure the cookie should be set with the correct HttpOnly, Secure, SameSite attributes.
Response.Cookies.Append("access-token", token, new CookieOptions
{
HttpOnly = true,
Secure = true, // Use in HTTPS environments
SameSite = SameSiteMode.Strict,
Expires = // Set expiration based on token validity
});
Finally, here are some resources about using access token and refresh token in asp core, you can refer to them:
Using Refresh Tokens in ASP.NET Core Authentication
Implementing JWT Refresh Token in ASP.NET Core MVC