Skip to content

Add serving of .well-known/passkey-endpoints to Identity - #68066

Merged
rolandVi merged 11 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:roland/passkeys
Aug 11, 2026
Merged

rolandVi merged 11 commits into
dotnet:rolandVi/passkey-workfrom
rolandVi:roland/passkeys

Conversation

@rolandVi

@rolandVi rolandVi commented Jul 28, 2026

Copy link
Copy Markdown
Member

API proposal in #68109.

This pull request introduces support for advertising passkey endpoints in ASP.NET Core Identity by implementing the well-known /.well-known/passkey-endpoints document, following the W3C specification. This enables credential managers to discover where users can enroll or manage passkeys for an application. The main changes include new configuration options, an endpoint that serves the document, and public APIs for easy integration.

Example usage

builder.Services.AddPasskeyEndpoints(options =>
{
    options.Enroll = "/Account/Manage/Passkeys";
    options.Manage = "/Account/Manage/Passkeys";
});

var app = builder.Build();

app.MapWellKnownPasskeyEndpoints();

Passkey endpoints support

  • Added the PasskeyEndpointsOptions class, allowing configuration of URLs for passkey enrollment, management and PRF usage details pages, which are advertised in the well-known passkey endpoints document.
  • Introduced the AddPasskeyEndpoints extension method to IServiceCollection, enabling applications to configure the advertised locations via DI.
  • Introduced the MapWellKnownPasskeyEndpoints extension method to IEndpointRouteBuilder, which serves the document at /.well-known/passkey-endpoints for anonymous GET and HEAD requests, and handles URL resolution and logging. Relative values are resolved against the incoming request, so they observe the real scheme and host behind a reverse proxy. Mapping it into a route group with a prefix throws at startup, because the specification requires the document at the root of the origin.
  • Added the PasskeyEndpointsResponse data contract and registered it with the JSON serializer context for correct serialization of the document.

Public API and sample usage

  • Updated the public API surface to expose the new configuration and extension methods, and added sample usage in IdentitySample.PasskeyUI and the Blazor Web template to demonstrate advertising a passkey enrollment endpoint.

Resolves #67300

Copilot AI review requested due to automatic review settings July 28, 2026 15:27
@rolandVi
rolandVi requested a review from a team as a code owner July 28, 2026 15:27
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 28, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @rolandVi. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds ASP.NET Core Identity support for advertising passkey enrollment/management locations via the well-known /.well-known/passkey-endpoints document (per the W3C draft), including DI wiring, middleware to serve the JSON document, serialization support, and coverage/tests plus template/sample updates.

Changes:

  • Introduces PasskeyEndpointsOptions and AddPasskeyEndpoints(...) to configure and enable the well-known passkey endpoints document.
  • Adds a startup filter (PasskeyEndpointsStartupFilter) that serves the document early in the pipeline (before routing/path-base adjustments) and performs URL resolution + logging.
  • Adds functional tests plus template/sample usage demonstrating configuration.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Program.Main.cs Template: adds AddPasskeyEndpoints configuration for passkey discovery.
src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Program.cs Template: same AddPasskeyEndpoints configuration for passkey discovery.
src/Identity/test/Identity.FunctionalTests/AddPasskeyEndpointsTests.cs Adds functional coverage for serving, URL resolution, host/path-base behaviors, and logging.
src/Identity/samples/IdentitySample.PasskeyUI/Program.cs Sample: demonstrates advertising an enroll endpoint via AddPasskeyEndpoints.
src/Identity/Core/src/PublicAPI.Unshipped.txt Declares new public API surface (options + service extension).
src/Identity/Core/src/PasskeyEndpointsStartupFilter.cs Implements middleware via startup filter to serve /.well-known/passkey-endpoints.
src/Identity/Core/src/PasskeyEndpointsServiceCollectionExtensions.cs Adds IServiceCollection.AddPasskeyEndpoints(...) public entry point + docs.
src/Identity/Core/src/PasskeyEndpointsOptions.cs Adds public options object for enroll/manage URL configuration + docs.
src/Identity/Core/src/Data/PasskeyEndpointsResponse.cs Adds internal response contract for JSON serialization.
src/Identity/Core/src/Data/IdentityEndpointsJsonSerializerContext.cs Registers the new response type for source-generated JSON serialization.

Comment thread src/Identity/Core/src/Data/PasskeyEndpointsResponse.cs
Comment thread src/Identity/Core/src/PasskeyEndpointsStartupFilter.cs Outdated
Comment thread src/Identity/Core/src/PasskeyEndpointsStartupFilter.cs Outdated
@javiercn
javiercn requested a review from a team July 28, 2026 15:32
Misleading comment

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@rokonec rokonec added area-identity Includes: Identity and providers and removed community-contribution Indicates that the PR has been added by a community member labels Jul 29, 2026
ArgumentNullException.ThrowIfNull(configure);

services.Configure(configure);
services.TryAddEnumerable(ServiceDescriptor.Transient<IStartupFilter, PasskeyEndpointsStartupFilter>());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Publishing a user-facing endpoint through IStartupFilter is unusual, and it forces this ahead of user middleware such as UseForwardedHeaders() which should influence link generation. This should follow the normal Add*/Map* pattern with an explicit MapWellKnownPasskeyEndpoints(). Can you open a separate API proposal following the API review process?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, fixed. The filter was there so the document couldn't be mapped where credential managers won't look, but it also ran before UseForwardedHeaders(). I'll open the API proposal

@rolandVi rolandVi Aug 3, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Publishing a user-facing endpoint through IStartupFilter is unusual, and it forces this ahead of user middleware such as UseForwardedHeaders() which should influence link generation. This should follow the normal Add*/Map* pattern with an explicit MapWellKnownPasskeyEndpoints(). Can you open a separate API proposal following the API review process?

I opened the API proposal at #68109. I will align the design with @rokonec, as he will champion it through API review.

Comment thread src/Identity/Core/src/PasskeyEndpointsOptions.cs Outdated
Comment thread src/Identity/Core/src/PasskeyEndpointsStartupFilter.cs Outdated
@rolandVi
rolandVi changed the base branch from main to rolandVi/passkey-work July 31, 2026 08:46
@rolandVi
rolandVi requested review from halter73 and rokonec and removed request for halter73 August 4, 2026 08:42

@rokonec rokonec left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the runtime behaviour with standalone harnesses (ASP.NET Core 10.0.10 and 11.0-preview.6) rather than reasoning from the diff. This is careful, well-tested work — the move from IStartupFilter to Map* was the right call, and conformance holds on every point the specification actually states.

One blocking item. The route-group guard throws from an endpoint convention. A PoC confirmed that whenever the authorization policy cache is not active — which includes any application with a custom or derived IAuthorizationPolicyProvider — the app starts cleanly and then returns 500 for every request, not just this endpoint. Details inline.

The rest are non-blocking: no Cache-Control/Vary on a body that varies by Host, an opaque AmbiguousMatchException if MapWellKnownPasskeyEndpoints() is called twice, a docs note on UseForwardedHeaders() ordering, and a few test-coverage gaps.

Consider: [Experimental]

Comment thread src/Identity/Core/src/PasskeyEndpointsEndpointRouteBuilderExtensions.cs Outdated
Comment thread src/Identity/Core/src/PasskeyEndpointsEndpointRouteBuilderExtensions.cs Outdated
Comment thread src/Identity/test/Identity.FunctionalTests/AddPasskeyEndpointsTests.cs Outdated
Comment thread src/Identity/Core/src/PasskeyEndpointsOptions.cs
@rolandVi
rolandVi requested a review from rokonec August 10, 2026 11:57
@rolandVi

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
3 pipeline(s) were filtered out due to trigger conditions.

@rolandVi

Copy link
Copy Markdown
Member Author

/azp run aspnetcore-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

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

Projects

None yet

4 participants