Reputation: 39058
I've set up the authorization like this, loosely following the three blogs here, here and here (basically making it wide open except for the validation of the expiration time).
string secret = "super-secret-password";
byte[] bytes = Encoding.ASCII.GetBytes(secret);
SymmetricSecurityKey key = new SymmetricSecurityKey(bytes);
TokenValidationParameters parameters = new TokenValidationParameters
{
IssuerSigningKey = key,
ValidateLifetime = true,
ValidateIssuerSigningKey = false,
ValidateIssuer = false,
ValidateAudience = false,
RequireAudience = false,
RequireExpirationTime = false,
RequireSignedTokens = false
};
services.AddAuthentication(_ => _.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(_ => _.TokenValidationParameters = parameters);
The token distributed is created like this.
string secret = "super-secret-password";
byte[] bytes = Encoding.ASCII.GetBytes(secret);
SymmetricSecurityKey key = new SymmetricSecurityKey(bytes);
Claim[] claims = {
new Claim("role", "basic"),
new Claim("role", "elevated"),
new Claim("name", name)
};
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddHours(1),
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature)
};
SecurityToken token = handler.CreateToken(descriptor);
return handler.WriteToken(token);
Then, I paste the returned string into JWT.io and it confirms that everything is great (valid signature and all that). However, when I use that token in Postman (it adds the header Bearer + my_token_string), the call gives me 401 unauthorized.
I tried two secure methods in my controller and one open (the latter works as expected).
[HttpGet("open"), AllowAnonymous]
public ActionResult OpenResult() { return Ok("Open result accessed."); }
[HttpGet("secure"), Authorize]
public ActionResult SecureResult() { return Ok("Secure result accessed."); }
[HttpGet("elevated"), Authorize(Roles = "elevated")]
public ActionResult ElevatedResult() { return Ok("Elevated result accessed."); }
I don't know what I might be missing. Even worse, I'm not sure how to investigate it further.
What can I do at this point?
This answer suggest setting headers. This answer is irrelevant for my relaxed case with no validation of audience. This answer gives nothing much, really. (Just making sure to show that I've done my effort.)
Upvotes: 1
Views: 310
Reputation: 1536
One thing to check is the ordering of "use" statements in Configure in Startup.cs. If you have app.UseAuthorization() before app.UseAuthentication() you'll get 401s. This has caught me before:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseRouting();
app.UseAuthentication(); //make sure this comes before app.UseAuthorization()
app.UseAuthorization();
app.UseHttpsRedirection();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHubService>("/notification");
});
}
Upvotes: 2