aspnetcore/security/authentication/passkeys/blazor.md
This guide explains how to implement passkey support for a new or existing Blazor Web App with ASP.NET Core Identity.
For an overview of passkeys and general configuration guidance, see xref:security/authentication/passkeys/index.
:::zone pivot="new-development"
.NET SDK (.NET 10 or later)
Use the following guidance to create a new Blazor Web App with ASP.NET Core Identity, which includes passkeys support.
[!NOTE] Visual Studio 2022 or later and .NET 10 or later SDK are required.
In Visual Studio:
BlazorWebAppPasskeys in the Project name field, including matching the capitalization. Using this exact project name is important to ensure that the namespaces match for code that you copy from the article into the app that you're building.This guidance assumes that you have familiarity with VS Code. If you're new to VS Code, see the VS Code documentation. The videos listed by the Introductory Videos page are designed to give you an overview of VS Code's features.
In VS Code:
Go to the Explorer view and select the Create .NET Project button. Alternatively, you can bring up the Command Palette using <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>, and then type ".NET" and find and select the .NET: New Project command.
Select the Blazor Web App project template from the list.
In the Project Location dialog, create or select a folder for the project.
In the Command Palette, name the project BlazorWebAppPasskeys, including matching the capitalization. Using this exact project name is important to ensure that the namespaces match for code that you copy from the article into the app that you're building.
Select Create project from the Command Palette.
In a command shell:
Change to the directory using the cd command to where you want to create the project folder (for example, cd c:/users/Bernie_Kopell/Documents).
Use the dotnet new command with the blazor project template to create a new Blazor Web App project. The -o|--output option passed to the command creates the project in a new folder named BlazorWebAppPasskeys at the current directory location.
[!IMPORTANT] Name the project
BlazorWebAppPasskeys, including matching the capitalization, so the namespaces match for code that you copy from the article to the app.
dotnet new blazor -au Individual -o BlazorWebAppPasskeys
The preceding instructions create a Blazor Web App with:
-au|--authentication option.[!NOTE] Currently, only the Blazor Web App project template includes built-in passkey support.
Press <kbd>F5</kbd> to run the app with debugging or <kbd>Ctrl</kbd>+<kbd>F5</kbd> to run the app without debugging.
Press <kbd>F5</kbd> to run the app with debugging or <kbd>Ctrl</kbd>+<kbd>F5</kbd> to run the app without debugging.
In a command shell opened to the root folder of the server BlazorWebAppPasskeys project, execute the following command:
dotnet watch
:::zone-end
:::zone pivot="existing-app"
The following guidance relies upon an app that was created with Individual Accounts for the app's Authentication type or scaffolding Identity into an existing app.
For migration guidance, see xref:migration/index.
The links in this article to .NET reference source load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
In Program.cs, update the Identity configuration to use schema version 3, which includes passkey support:
builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
In Visual Studio Solution Explorer, double-click Connected Services. In the Service Dependencies area, select the ellipsis (...) followed by Add migration in the SQL Server Express LocalDB area.
Give the migration a Migration name of AddPasskeySupport to describe the migration. Wait for the database context to load in the DbContext class names field. Select Finish to create the migration. Select the Close button when the operation completes.
Select the ellipsis (...) again followed by the Update database command.
The Update database with the latest migration dialog opens. Wait for the DbContext class names field to update and for prior migrations to load. Select the Finish button. Select the Close button when the operation completes.
Use the following command in the Terminal (Terminal menu > New Terminal) to add a migration for the new data annotations:
dotnet ef migrations add AddPasskeySupport
To apply the migration to the database, execute the following command:
dotnet ef database update
To add a migration for the new data annotations, execute the following command in a command shell opened to the project's root folder:
dotnet ef migrations add AddPasskeySupport
To apply the migration to the database, execute the following command:
dotnet ef database update
Add the following model classes to the project in the Components/Account folder and update the BlazorWebCSharp._1.Components.Account namespace to match the app (for example: Contoso.Components.Account):
Components/Account/PasskeyInputModel.cs: Holds the JSON passkey credential for passkey sign-in operations (Login component) and adding passkeys (Passkeys component).Components/Account/PasskeyOperation.cs: Defines the authentication action to be performed (PassKeySubmit component), either registering a new passkey (Create/0) or authenticating with an existing passkey (Request/1).PasskeySubmit componentAdd the following PasskeySubmit component to handle passkey operations:
Components/Account/Shared/PasskeySubmit.razor
Add the following JavaScript file to handle WebAuthn API interactions:
Components/Account/Shared/PasskeySubmit.razor.js
Update the IdentityComponentsEndpointRouteBuilderExtensions.cs file (or create the file if it doesn't exist and call MapAdditionalIdentityEndpoints in the Program file) to include the passkey-specific endpoints:
/PasskeyCreationOptions and /PasskeyRequestOptions endpoints
Replace the existing Login component with the following component and update the BlazorWebCSharp._1.Data namespace to match the app (for example: Contoso.Components.Account.Data):
Components/Account/Pages/Login.razor
IdentityRedirectManager classAdd the following method to the IdentityRedirectManager class in Components/Account/IdentityRedirectManager.cs:
public void RedirectToInvalidUser(
UserManager<ApplicationUser> userManager, HttpContext context) =>
RedirectToWithStatus("Account/InvalidUser",
$"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.",
context);
Add the following Passkeys component for managing passkeys and update the BlazorWebCSharp._1.Data namespace to match the app (for example: Contoso.Components.Account.Data):
Components/Account/Pages/Manage/Passkeys.razor
Add the following RenamePasskey component for renaming passkeys and update the BlazorWebCSharp._1.Data namespace to match the app (for example: Contoso.Components.Account.Data):
Components/Account/Pages/Manage/RenamePasskey.razor
Add a link to the passkey management page in the app's ManageNavMenu component.
In Components/Account/Shared/ManageNavMenu.razor, add the following NavLink component for the Passkeys component:
<li class="nav-item">
<NavLink class="nav-link" href="Account/Manage/Passkeys">Passkeys</NavLink>
</li>
In the App component (Components/App.razor), locate the Blazor script tag:
<script src="_framework/blazor.web.js"></script>
Immediately after the Blazor script tag, add a reference to the PasskeySubmit JavaScript module:
<script src="Components/Account/Shared/PasskeySubmit.razor.js" type="module"></script>
:::zone-end
To test passkey functionality:
After a passkey is registered:
Account/Manage/Passkeys to add, rename, or delete passkeys.PublicKeyCredential.toJSON error (TypeError: Illegal invocation)Some password managers don't implement the PublicKeyCredential.toJSON method correctly, which is required for JSON.stringify to work when serializing passkey credentials. When registering or authenticating a user with an app based on the Blazor Web App project template, the following error is thrown when attempting to add a passkey:
:::no-loc text="Error: Could not add a passkey: Illegal invocation":::
For guidance on mitigating this error, see xref:security/authentication/passkeys/index#mitigate-publickeycredentialtojson-error-typeerror-illegal-invocation.