WebAuthn
Create passkey (public-key) credentials and verify them with the Web Authentication API - biometrics, platform authenticators and security keys, driven entirely from C#.
@inject Bit.Butil.WebAuthn webAuthnMDN reference
Returns true when the browser exposes the Web Authentication API. WebAuthn requires a secure context, so expect false on plain http origins (localhost is exempt).
@inject Bit.Butil.WebAuthn webAuthn
var isAvailable = await webAuthn.IsAvailable();Registers a new public-key credential with a platform authenticator (Windows Hello, Touch ID, Android biometrics). The options object mirrors PublicKeyCredentialCreationOptions; Butil accepts any serializable shape - anonymous objects, JsonElement or your own typed classes via the generic overload. The returned JsonElement carries the credential id, rawId and attestation response.
var result = await webAuthn.CreateCredential(new
{
challenge = "testChallenge",
rp = new { name = "testRp" },
attestation = "direct",
user = new { id = "userId", name = "testUser", displayName = "testUser" },
authenticatorSelection = new { authenticatorAttachment = "platform" },
pubKeyCredParams = new object[]
{
new { alg = -7, type = "public-key" }, // ES256
new { alg = -8, type = "public-key" }, // Ed25519
new { alg = -257, type = "public-key" } // RS256
}
});
var credentialId = result.GetProperty("id").ToString();Asks the authenticator to sign a challenge with an existing credential, producing an assertion your server would verify. Passing the previously created rawId in allowCredentials narrows the request to that passkey; an empty list lets the browser offer any discoverable credential for this origin.
var options = createdRawId is null
? new { challenge = "test", allowCredentials = new object[] { } }
: new { challenge = "test", allowCredentials = new object[] { new { id = createdRawId, type = "public-key" } } };
var assertion = await webAuthn.GetCredential(options);
var credentialId = assertion.GetProperty("id").ToString();A convenience wrapper for the common re-authentication gesture: on first call it creates a Butil-managed credential and remembers its rawId in LocalStorage; on later calls it requests an assertion for that credential. Returns true when the user completes the native verification, false otherwise. Pass forceCreate to discard the remembered credential and register a fresh one.
var verified = await webAuthn.Verify();
// re-register instead of asserting the remembered credential:
var reRegistered = await webAuthn.Verify(forceCreate: true);API reference
Task<bool> IsAvailable()Task<JsonElement> CreateCredential(object options)Task<JsonElement> CreateCredential(JsonElement options)Task<TResult> CreateCredential<TValue, TResult>(TValue options)Task<JsonElement> GetCredential(object options)Task<JsonElement> GetCredential(JsonElement options)Task<TResult> GetCredential<TValue, TResult>(TValue options)Task<bool> Verify(bool forceCreate = false)