Reputation: 115
I'm using Asp.Net Core 5, and Asp.Net Identity with EFcore. I've followed parts of many video tutorials, advice posted here on SO and this very helpful article to get my project to the point where I'm at least getting 401's. My problem is now that I can't understand why I am getting 401's. I've validated my token with my secret on jwt.io and everything tells me that it should be working, but it is not. I am at a complete loss. Enough fluff, down to business.
My Startup Class. Note: in the OnMessageReceived event context.Token is null until I set it with the authorization header.
//imports
namespace auto_highlighter_iam
{
public class Startup
{
private readonly IConfiguration _config;
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration config, IWebHostEnvironment env)
{
_config = config;
_env = env;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(options =>
{
options.UseNpgsql(_config.GetConnectionString("AutoHighlighterIAMDev"));
});
IdentityBuilder iBuilder = services.AddIdentityCore<IdentityUser>(options =>
{
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._ ";
options.Password.RequiredLength = 12;
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = true;
//options.SignIn.RequireConfirmedEmail = true;
});
iBuilder = new IdentityBuilder(iBuilder.UserType, typeof(IdentityRole), iBuilder.Services)
.AddEntityFrameworkStores<DataContext>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddSignInManager<SignInManager<IdentityUser>>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(config =>
{
config.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
// Interesting note here. before this next line context.Token is null, but the authorization header has the jwt
context.Token = context.Request.Headers[HeaderNames.Authorization];
// Although the previous line successfully set context.Token to the jwt still getting 401's
return Task.CompletedTask;
}
};
config.RequireHttpsMetadata = !_env.IsDevelopment();
config.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true, //tried as false
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:Secret"])),
ValidateIssuer = true, //tried as false
ValidIssuer = _config["JWT:Iss"],
ValidateAudience = true, //tried as false
ValidAudience = _config["JWT:Aud"]
};
});
services.AddAuthorization();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "auto_highlighter_iam", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Insert JWT with Bearer into field",
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
dataContext.Database.Migrate();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "auto_highlighter_iam v1"));
}
app.UseExceptionHandler("/exception");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
My AuthorizationController. There are three endpoints. Two to test the roles I have and one that should test for any valid jwt. All of them return a 401.
// imports
namespace auto_highlighter_iam.Controllers
{
[ApiController]
[Route("/api-v1/[controller]")]
public class AuthorizationController : ControllerBase
{
[HttpGet("[action]")]
[Authorize(Roles = "SUPERADMIN")]
public IActionResult TestSuperAdmin()
{
return Ok();
}
[HttpGet("[action]")]
[Authorize(Roles = "DEFAULT")]
public IActionResult TestDefault()
{
return Ok();
}
[HttpGet("[action]")]
[Authorize]
public IActionResult TestAny()
{
return Ok();
}
}
}
The JWT I am testing with (pretend the token isn't expired, I've been making sure it's valid)
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJWSUVXIjoiRmFsc2UiLCJFRElUIjoiRmFsc2UiLCJERUxFVEUiOiJGYWxzZSIsIkNSRUFURSI6IkZhbHNlIiwicm9sZXMiOiJERUZBVUxUIiwibmJmIjoxNjExMTIxNTI1LCJleHAiOjE2MTExMjUxMjUsImlzcyI6ImF1dG8taGlnaGxpZ2h0ZXItaWFtIiwiYXVkIjoiYXV0by1oaWdobGlnaHRlci1mcm9udC1lbmQifQ.jnbW552pr7kylc82-4FmJJMmaeu7LQ7L48M5cdnSzuMsA1yRuts9sXUQ2_ok41SqX8mFpi7yreJJXGlE6qC1vA
The request I am sending
curl --location --request GET 'http://localhost:5000/api-v1/Authorization/TestAny' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJWSUVXIjoiRmFsc2UiLCJFRElUIjoiRmFsc2UiLCJERUxFVEUiOiJGYWxzZSIsIkNSRUFURSI6IkZhbHNlIiwicm9sZXMiOiJERUZBVUxUIiwibmJmIjoxNjExMTIwMDkzLCJleHAiOjE2MTExMjM2OTMsImlzcyI6ImF1dG8taGlnaGxpZ2h0ZXItaWFtIiwiYXVkIjoiYXV0by1oaWdobGlnaHRlci1mcm9udC1lbmQifQ.zOsNADvKGx1FYkzKLX4K53Y185dHFiM408aAjinQUQrVWQ_spXClozOAvp2glgiQkM0IwkDneB4Q_JCpQfet1g'
I'll be quick to provide any more info if I missed anything.
Upvotes: 1
Views: 471
Reputation: 7190
You need to put your middleware:
app.UseAuthentication();
before your app.UseAuthorization();
Like this :
app.UseAuthentication();
app.UseAuthorization();
Update:
And you need to change your request to(delete Bearer
):
curl --location --request GET 'http://localhost:5000/api-v1/Authorization/TestAny' \
--header 'Authorization: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJWSUVXIjoiRmFsc2UiLCJFRElUIjoiRmFsc2UiLCJERUxFVEUiOiJGYWxzZSIsIkNSRUFURSI6IkZhbHNlIiwicm9sZXMiOiJERUZBVUxUIiwibmJmIjoxNjExMTIwMDkzLCJleHAiOjE2MTExMjM2OTMsImlzcyI6ImF1dG8taGlnaGxpZ2h0ZXItaWFtIiwiYXVkIjoiYXV0by1oaWdobGlnaHRlci1mcm9udC1lbmQifQ.zOsNADvKGx1FYkzKLX4K53Y185dHFiM408aAjinQUQrVWQ_spXClozOAvp2glgiQkM0IwkDneB4Q_JCpQfet1g'
Upvotes: 1