Add serving of .well-known/passkey-endpoints to Identity - #68066
Conversation
|
Thanks for your PR, @rolandVi. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
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
PasskeyEndpointsOptionsandAddPasskeyEndpoints(...)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. |
Misleading comment Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| ArgumentNullException.ThrowIfNull(configure); | ||
|
|
||
| services.Configure(configure); | ||
| services.TryAddEnumerable(ServiceDescriptor.Transient<IStartupFilter, PasskeyEndpointsStartupFilter>()); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Publishing a user-facing endpoint through
IStartupFilteris unusual, and it forces this ahead of user middleware such asUseForwardedHeaders()which should influence link generation. This should follow the normalAdd*/Map*pattern with an explicitMapWellKnownPasskeyEndpoints(). 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.
rokonec
left a comment
There was a problem hiding this comment.
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]
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 3 pipeline(s) were filtered out due to trigger conditions. |
|
/azp run aspnetcore-ci |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
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-endpointsdocument, 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
Passkey endpoints support
PasskeyEndpointsOptionsclass, allowing configuration of URLs for passkey enrollment, management and PRF usage details pages, which are advertised in the well-known passkey endpoints document.AddPasskeyEndpointsextension method toIServiceCollection, enabling applications to configure the advertised locations via DI.MapWellKnownPasskeyEndpointsextension method toIEndpointRouteBuilder, which serves the document at/.well-known/passkey-endpointsfor 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.PasskeyEndpointsResponsedata contract and registered it with the JSON serializer context for correct serialization of the document.Public API and sample usage
IdentitySample.PasskeyUIand the Blazor Web template to demonstrate advertising a passkey enrollment endpoint.Resolves #67300