Skip to content

[release/8.0-preview4] Add MapIdentityApi<TUser>() #47927

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

Merged

Conversation

halter73
Copy link
Member

@halter73 halter73 commented Apr 27, 2023

Backport of #47414 to release/8.0-preview4

Add MapIdentityApi<TUser>()

This adds new API to add Identity API endpoints for user registration and login supporting both cookies and opaque bearer tokens. To support this, this PR also adds a BearerTokenHandler for authentication.

Description

MapIdentity<TUser>() adds two new API endpoints (/register and /login) to the IEndpointRouteBuilder (typically a WebApplication or RouteGroupBuilder). Additional features like 2fa and email verification will come in preview 5. See https://github.com/dotnet/aspnetcore/issues?q=is%3Aopen+label%3Afeature-token-identity+sort%3Aupdated-desc for a comprehensive list of planned features.

Usage Example

Server

Bearer token and cookies enabled

// usings ... 

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddDbContext<ApplicationDbContext>(
    options => options.UseSqlite(builder.Configuration["ConnectionString"]));

builder.Services.AddIdentityEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

var app = builder.Build();

app.MapGroup("/identity").MapIdentity<IdentityUser>();

app.MapGet("/requires-auth", (ClaimsPrincipal user) => $"Hello, {user.Identity?.Name}!").RequireAuthorization();

app.Run();

// public class ApplicationDbContext : IdentityDbContext<IdentityUser> ...

Client

Assume httpClient, username and password are already initialized.

Register

// Email confirmation will be added later.
// The request body is: { "username": "<username>", "password": "<password>" }
await httpClient.PostAsJsonAsync("/identity/register", new { username, password });

Login (Bearer token)

// 2fa flow will be added later.
// The request body is: { "username": "<username>", "password": "<password>" }
var loginResponse = await httpClient.PostAsJsonAsync("/identity/login", new { username, password });

// loginResponse is similar to the "Access Token Response" defined in the OAuth 2 spec
// {
//   "token_type": "Bearer",
//   "access_token": "...",
//   "expires_in": 3600
// }
// refresh token is likely to be added later
var loginContent = await loginResponse.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = loginContent.GetProperty("access_token").GetString();

httpClient.DefaultRequestHeaders.Authorization = new("Bearer", accessToken);
Console.WriteLine(await httpClient.GetStringAsync("/requires-auth"));

Login (Cookie)

// HttpClientHandler.UseCookies is true by default on supported platforms.
// The request body is: { "username": "<username>", "password": "<password>" }
await httpClient.PostAsJsonAsync("/identity/login?cookieMode=true", new { username, password });

Console.WriteLine(await cookieClient.GetStringAsync("/requires-auth"));

Customer Impact

This allows customers to give feedback on our early work to improve the identity experience for SPA and mobile applications. #42158 which is about improving the is experience is one of aspnetcore's most upvoted issues.

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

This PR mostly adds new API. The only other impact is adding new assembly to the aspnetcore shared runtime (Microsoft.AspNetCore.Authentication.BearerToken.dll) and marking Microsoft.AspNetCore.Identity.dll as non-trimmable.

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

Is there anyone specifically who should review the addition of Microsoft.AspNetCore.Authentication.BearerToken to the aspnetcore shared runtime?

@halter73 halter73 requested review from a team, Tratcher and wtgodbe as code owners April 27, 2023 18:32
@ghost ghost added the area-identity Includes: Identity and providers label Apr 27, 2023
@halter73 halter73 added the Servicing-consider Shiproom approval is required for the issue label Apr 27, 2023
@ghost
Copy link

ghost commented Apr 27, 2023

Hi @halter73. Please make sure you've updated the PR description to use the Shiproom Template. Also, make sure this PR is not marked as a draft and is ready-to-merge.

To learn more about how to prepare a servicing PR click here.

@halter73 halter73 added Servicing-approved Shiproom has approved the issue and removed Servicing-consider Shiproom approval is required for the issue labels Apr 27, 2023
@ghost
Copy link

ghost commented Apr 27, 2023

Hi @halter73. This PR was just approved to be included in the upcoming servicing release. Somebody from the @dotnet/aspnet-build team will get it merged when the branches are open. Until then, please make sure all the CI checks pass and the PR is reviewed.

@halter73
Copy link
Member Author

@dotnet/aspnet-build Can someone please merge this? Thanks!

@wtgodbe wtgodbe merged commit 8d63ed2 into release/8.0-preview4 Apr 28, 2023
@wtgodbe wtgodbe deleted the backport/pr-47414-to-release/8.0-preview4 branch April 28, 2023 00:16
@ghost ghost added this to the 8.0-preview4 milestone Apr 28, 2023
@ghost ghost added the area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework label Apr 28, 2023
@kohanyirobert
Copy link

@halter73 Not sure whether this is the best to place to enquire info about this, but here goes nothing.

As I understand this change supports scenarios when one would use the "with React" template for a new project with "Individual Login" (which in turn means using Identity). Cool stuff 👏

My question: when rolling our own AccountController or such with a Login endpoint is there/will there be any new features/changes in .NET 8 (preview?) regarding not using Identity only cookie authn?

For example, currently using cookie authn in such a scenario

builder.Services.AddAuthentication()
    .AddCookie();

and having a reeeaallllllly simple an endpoint for login like

[HttpPost("Login")]
public async Task<IActionResult> Login([FromForm]string email, [FromForm]string password)
{
    if (email != "admin@admin" && password != "admin")
    {
        return Unauthorized();
    }
    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        ...

when protecting endpoints like

[HttpGet]
[Authorize]
public string Secret()
{
    return "Only can see this after login.";
}

one would receive 302 HTTP responses redirecting to https://localhost:44487/Account/Login? or similar because of the defaults for cookie authn. Hope I made sense :)

Some context: I'm a developer/educator and this particular weirdness trips up newcomers to the .NET/ASP.NET + SPA ecosystem in particular. (Lot of things to trip up upon :D)

Thank you for your time!

@ghost
Copy link

ghost commented Jun 10, 2023

Hi @kohanyirobert. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-identity Includes: Identity and providers area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework Servicing-approved Shiproom has approved the issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants