-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Epic]: Configuring minimal APIs for auth should be suitably simple & featured #34545
Comments
Thanks for contacting us. We're moving this issue to the |
@DamianEdwards @davidfowl @LadyNaggaga do we have a minimum set of authz providers we wish to support? "that which we support now," meaning Microsoft Identity Platform (MIP/AAD), ASP.NET Core identity, and identity server? I'd prioritize them in that order, tbh. |
I don't know the scope of this work, this doesn't even work by default (AFAIK) using MVC, so it's low on the priority list IMO. |
Right, we need to figure out what's required here. It wasn't intended to be a "make the thing work automagically" but rather to force us to actually try it (I think @glennc started) and if anything falls out of that that's considered a real showstopper then it would get paged-in. |
Wow OK, so the actual adding auth & CORS to the app isn't bad at all, but configuring Swashbuckle to support the auth scheme is quite a lot of code. |
Items to consider:
I have written some raw thoughts in the following gist: https://gist.github.com/rafikiassumani-msft/1c8bfa9b4b05444a5473efe2ecbe7191 |
I had originally categorized this under the OpenAPI work in #34514. Since this topic isn't strictly related to OpenAPI + auth, I'm removing it from that epic. Note: we have another issue that more specifically tracks OpenAPI + auth. |
@davidfowl and I chatted about this briefly last week and got the start of an idea. Not saying much I know but we'll look into it a bit more and report back. General gist of the idea is to elevate authnz configuration to a builder-level concern and auto-add the required services and middleware, along the lines of: var builder = WebApplication.CreateBuilder();
// Top-level auth configuration, auto-adds required middleware to pipeline after routing middleware
builder.ConfigureAuthentication(AuthenticationKind.JwtBearer);
// Or perhaps a property?
builder.Authentication.Kind = AuthenticationKind.JwtBearer;
// Maybe overloads of Create/CreateBuilder?
// var builder = WebApplication.CreateBuilder(AuthenticationKind.JwtBearer);
// Maybe simple top-level policy too
builder.Authorization.AddPolicy("todo:read-write",
p => p.RequireAuthenticatedUser().RequireClaim("scope", "todo:read-write")
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSqlite<TodoDb>("Data Source=todos.db");
var app = builder.Builder();
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync());
app.MapGet("/todos/{id}", async (int id, TodoDb db) => await db.Todos.FindAsync(id) is Todo todo
? Results.Ok(todo)
: Results.NotFound())
app.MapPost("/todos", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todos/{todo.Id}", todo);
})
// This will throw at startup if authentication is not configured
.RequireAuthorization("todo:read-write");
app.MapDelete("/todos/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.Ok(todo);
}
return Results.NotFound();
})
// Inline simple user claims checking, potentially need to figure out lifetime issues of these though
.RequireAuthorization(user => user.HasClaim("scope", "todo:delete"));
app.Run();
class Todo
{
public int Id { get; set; }
public string? Title { get; set; }
public bool IsComplete { get; set; }
}
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
} |
@DamianEdwards This is a good start for the discussion, a few things to consider:
app.MapDelete("/todo/{id}", async (int id, Todo todo) => {...} )
.RequireAuthorization(user => user.HasClaim("scope", "todo:delete")
.RequireAuthorization(user => user.HasClaim("groups", "admin"); There are some nuances to clarify.
app.MapDelete("/todo/{id}", async (int id, Todo todo) => {...} )
.RequireAuthorization(principal => principal.HasScopes("scope1", "scope2", ...)
app.MapDelete("/todo/{id}", async (int id, Todo todo) => {...} )
.RequireAuthorization(principal => principal.HasClaim("roles", "can:delete")
.RequireAuthorization(principal => principal .HasClaim("groups", "admin"); Notice that I am using
|
@rafikiassumani-msft yep treat my example as pseudo-code at best. Lots of details to consider. |
How do you add custom attributes with the minimal API? |
@bloggrammer What do you mean exactly? |
@davidfowl please, look at this answer on SO (https://stackoverflow.com/a/68974923/12476466). How can you implement such for a minimal API such that you can return a custom result like |
I thought I'd add my 2 cents as a recent user of the minimal apis. I gave up on figuring out how the 'frame work' did auth and logging and config files -- for auth, everything was worded as "JWT", and too many builders and factories to comprehend, and I just want a generic header validator -- so I just did this: https://github.com/kjpgit/techdemo/blob/274811d854d614bb09966983153ebc2339db1504/dotnet_ultra_minimal/program.cs#L96-L108 And honestly, I like it. The MyUserContext is passed in explicitly to each function, or raises an exception if it can't be constructed, so you know it's correct unlike an [Attribute] which was silently ignored(!) when I tried it at the class level. If your "new simple solution" isn't as simple as what I did... basically a few lines of code... I see no reason to switch :-) On one person projects, just an |
I think it would be good if you could define the scheme as well and include support for multiple schemes. (Also on the group function/method wrapping the minimal APIs) |
Different to how that is done today? These are normal auth policies. app.MapGet("/", () => "Hello World!")
.RequireAuthorization(pb => pb.AddAuthenticationSchemes("Foo").RequireClaim("claim")); |
Looks like to need to try this and read the docs :) This is perfect. Could I apply something like this to a group of minimal APIs as well? |
Yep. Either by passing the policy to many endpoints or using the new grouping feature coming in next .NET 7 preview. |
Thanks for contacting us. We're moving this issue to the |
Configuring authentication and authorization requirements for minimal APIs should be suitably inline with the overall experience.
[ ] Introduce support for defining Authorization policies via Configuration #42172[ ] Automatically inferOpenApiSecuritySchemes
from authentication configuration #39761[ ] Support config-based options for different authentication schemes #42170The text was updated successfully, but these errors were encountered: