File: Program.cs
Web Access
Project: src\src\Identity\samples\IdentitySample.PasskeyUI\IdentitySample.PasskeyUI.csproj (IdentitySample.PasskeyUI)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using IdentitySample.PasskeyUI;
using IdentitySample.PasskeyUI.Components;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.Mvc;
 
var builder = WebApplication.CreateBuilder(args);
 
builder.Services.AddRazorComponents();
builder.Services.AddCascadingAuthenticationState();
 
builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddIdentityCookies();
 
builder.Services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = options =>
    {
        options.HttpContext.Response.Redirect("/");
        return Task.CompletedTask;
    };
});
 
builder.Services.AddAuthorization();
 
builder.Services.AddIdentityCore<PocoUser>()
    .AddSignInManager()
    .AddDefaultTokenProviders();
 
builder.Services.AddSingleton<IUserStore<PocoUser>, InMemoryUserStore<PocoUser>>();
builder.Services.AddSingleton<IUserPasskeyStore<PocoUser>, InMemoryUserStore<PocoUser>>();
 
var app = builder.Build();
 
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>();
 
app.MapPost("attestation/options", async (
    [FromServices] UserManager<PocoUser> userManager,
    [FromServices] SignInManager<PocoUser> signInManager,
    [FromBody] PublicKeyCredentialCreationOptionsRequest request) =>
{
    var userId = (await userManager.FindByNameAsync(request.Username) ?? new PocoUser()).Id;
    var userEntity = new PasskeyUserEntity
    {
        Id = userId,
        Name = request.Username,
        DisplayName = request.Username
    };
    var optionsJson = await signInManager.MakePasskeyCreationOptionsAsync(userEntity);
    return Results.Content(optionsJson, contentType: "application/json");
});
 
app.MapPost("assertion/options", async (
    [FromServices] UserManager<PocoUser> userManager,
    [FromServices] SignInManager<PocoUser> signInManager,
    [FromBody] PublicKeyCredentialGetOptionsRequest request) =>
{
    var user = !string.IsNullOrEmpty(request.Username) ? await userManager.FindByNameAsync(request.Username) : null;
    var optionsJson = await signInManager.MakePasskeyRequestOptionsAsync(user);
    return Results.Content(optionsJson, contentType: "application/json");
});
 
app.MapPost("account/logout", async (
    [FromServices] SignInManager<PocoUser> signInManager) =>
{
    await signInManager.SignOutAsync();
    return TypedResults.LocalRedirect($"~/");
});
 
app.Run();
 
sealed class PublicKeyCredentialCreationOptionsRequest
{
    public required string Username { get; set; }
}
 
sealed class PublicKeyCredentialGetOptionsRequest
{
    public string? Username { get; set; }
}