Nethereum.WebAuthn.Blazor
7.0.0
Prefix Reserved
dotnet add package Nethereum.WebAuthn.Blazor --version 7.0.0
NuGet\Install-Package Nethereum.WebAuthn.Blazor -Version 7.0.0
<PackageReference Include="Nethereum.WebAuthn.Blazor" Version="7.0.0" />
<PackageVersion Include="Nethereum.WebAuthn.Blazor" Version="7.0.0" />
<PackageReference Include="Nethereum.WebAuthn.Blazor" />
paket add Nethereum.WebAuthn.Blazor --version 7.0.0
#r "nuget: Nethereum.WebAuthn.Blazor, 7.0.0"
#:package Nethereum.WebAuthn.Blazor@7.0.0
#addin nuget:?package=Nethereum.WebAuthn.Blazor&version=7.0.0
#tool nuget:?package=Nethereum.WebAuthn.Blazor&version=7.0.0
Nethereum.WebAuthn.Blazor
Nethereum.WebAuthn.Blazor implements Nethereum.WebAuthn's
IWebAuthnAuthenticator / IWebAuthnCredentialFactory over the browser's real passkey store
(navigator.credentials), so a Blazor Server or WebAssembly app gets OS-native passkeys - Windows
Hello, Touch ID, Android biometrics, security keys - with almost no app code.
Installation
dotnet add package Nethereum.WebAuthn.Blazor
Registering the authenticator
// Program.cs
builder.Services.AddNethereumWebAuthnBlazor();
public static IServiceCollection AddNethereumWebAuthnBlazor(
this IServiceCollection services,
bool requireUserVerificationForAssertion = true)
This registers a single scoped BlazorWebAuthnAuthenticator under both IWebAuthnAuthenticator and
IWebAuthnCredentialFactory - scoped so it shares one JS module instance per Blazor circuit (Server)
or app lifetime (WebAssembly), matching the lifetime of the injected IJSRuntime itself.
requireUserVerificationForAssertion controls the user-verification requirement passed to
navigator.credentials.get for every assertion (registration's requirement is set per-call, via
WebAuthnCredentialCreationOptions.RequireUserVerification - see below).
Usage
Inject IWebAuthnCredentialFactory and IWebAuthnAuthenticator into a component or service - both
resolve to the same registered BlazorWebAuthnAuthenticator:
using System.Threading.Tasks;
using Nethereum.WebAuthn;
public class PasskeyService
{
private readonly IWebAuthnCredentialFactory _credentialFactory;
private readonly IWebAuthnAuthenticator _authenticator;
public PasskeyService(IWebAuthnCredentialFactory credentialFactory, IWebAuthnAuthenticator authenticator)
{
_credentialFactory = credentialFactory;
_authenticator = authenticator;
}
public async Task<WebAuthnAccountSigningService> RegisterAsync()
{
var created = await _credentialFactory.CreateCredentialAsync(new WebAuthnCredentialCreationOptions
{
RpId = "nethereum.local",
RpName = "My Nethereum App",
UserName = "alice",
RequireUserVerification = true
});
// credentialId is the ON-CHAIN id (keccak of the public key); platformCredentialId is the
// browser's own credential handle used to select the passkey for the assertion - see
// Nethereum.WebAuthn's two-id model.
return new WebAuthnAccountSigningService(
_authenticator, created.OnChainCredentialId, rpId: "nethereum.local",
platformCredentialId: created.PlatformCredentialId);
}
}
This is the browser-backed half of a passkey account. For the ERC-7579 validator module, the account
init data, and the full create + send flow through IAAClient, see
Nethereum.AccountAbstraction.WebAuthn's Quick
Start - it uses SoftwareWebAuthnAuthenticator for a runnable example, and swapping it for the
BlazorWebAuthnAuthenticator registered here is a one-line change; nothing else in that flow differs.
RP-ID and origin scoping
RpId is the relying-party id the browser scopes the passkey to - it must be the page's own domain
(or a registrable parent of it) or navigator.credentials rejects the call outright. A passkey
registered under one RP ID cannot be asserted under another. Keep the RpId you pass to
CreateCredentialAsync and the rpId you pass to WebAuthnAccountSigningService identical, and
matching the on-chain validator's expectations for that account (the on-chain WebAuthnValidator
does not itself check the RP ID - the browser does, before the assertion is ever produced).
Blazor Server vs. WebAssembly
BlazorWebAuthnAuthenticator works unmodified under either render mode - it talks to the browser
exclusively through IJSRuntime interop and never touches the DOM directly:
- Blazor Server: interop round-trips over the SignalR circuit. The scoped registration means one authenticator instance (and one imported JS module) per circuit.
- WebAssembly: interop is an in-process JS call. The scoped registration is effectively a singleton for the app's lifetime, since a WASM app has one "scope."
All byte[] payloads cross the JS interop boundary as base64/base64url strings, since Blazor does not
marshal byte[] uniformly across Server and WebAssembly render modes.
Notes
- All parsing (DER signatures, SPKI/COSE public keys, authenticatorData) is delegated to
Nethereum.WebAuthn.WebAuthnResponseParser- this package only bridges JS interop. - The JS module lives at
wwwroot/nethereumWebAuthn.jsand is served from_content/Nethereum.WebAuthn.Blazor/nethereumWebAuthn.js(the standard Razor class library static web assets path) - no manual<script>reference is needed. - The live browser passkey path (an actual OS prompt) cannot run in a headless test suite; it is
exercised manually via the Blazor AA demo. The unit tests in
tests/Nethereum.WebAuthn.Blazor.UnitTestsinstead verify the C# ↔ JS marshalling against real BCL-generated P-256 keys/signatures fed through a fakeIJSRuntime.
Related Packages
- Nethereum.WebAuthn - the platform-agnostic seams, the two-id model,
SoftwareWebAuthnAuthenticator - Nethereum.AccountAbstraction.WebAuthn - the ERC-7579 validator module + end-to-end account create/send flow
- Nethereum.WebAuthn.Windows - the desktop (Windows Hello) equivalent of this package
Additional Resources
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.0)
- Nethereum.WebAuthn (>= 7.0.0)
- Newtonsoft.Json (>= 11.0.2 && < 14.0.0)
-
net8.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.0)
- Nethereum.WebAuthn (>= 7.0.0)
- Newtonsoft.Json (>= 11.0.2 && < 14.0.0)
-
net9.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.0)
- Nethereum.WebAuthn (>= 7.0.0)
- Newtonsoft.Json (>= 11.0.2 && < 14.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 7.0.0 | 103 | 10/2/2026 |