WebAuthn
Namespace: Wisej.Ext.WebAuthn
Assembly: Wisej.Ext.WebAuthn (4.1.0.0)
Provides methods for creating and retrieving credentials from the client following the Web Authentication API standards.
- C#
- VB.NET
public static class WebAuthn
Public Class WebAuthn
See https://w3c.github.io/webauthn/.
Methods
CreateAsync(challenge, rp, user, publicKeyCredentialParameters, authenticatorSelection, timeout, attestation)
Creates new credentials for the client.
| Parameter | Type | Description |
|---|---|---|
| challenge | String | A base64-encoded random value generated by the server for validating the request. |
| rp | RelyingParty | The Relying Party (RP), the organization responsible for registering and authenticating the user. |
| user | PublicKeyCredentialUserEntity | Information about the user currently registering. |
| publicKeyCredentialParameters | PublicKeyCredentialParameters[] | Array describing what public key types are acceptable to the server, in order of preference. |
| authenticatorSelection | AuthenticatorSelectionCriteria | Requirements for the authenticator, such as "platform" (Windows Hello) vs "cross-platform" (YubiKey). |
| timeout | Int32 | The time in milliseconds that the user has to respond to a prompt for registration. |
| attestation | AttestationConveyancePreference | Indicates how important the attestation data is to this registration event. |
Returns: Task<CredentialsResponse>. A CredentialsResponse whose PublicKey contains the new public key.
Save CredentialID and the PublicKey with the user account: they are needed to call GetAsync and Validate when the user logs in.
Throws:
- Exception The browser rejected the request, e.g. the user cancelled or the operation timed out.
Example:
private async void buttonRegister_Click(object sender, EventArgs e)
{
// Generate a random challenge, base64 encoded.
var bytes = new byte[32];
using (var rng = RandomNumberGenerator.Create())
rng.GetBytes(bytes);
string challenge = Convert.ToBase64String(bytes);
var rp = new RelyingParty("example.com", "Example Inc.");
var user = new PublicKeyCredentialUserEntity("user-1234", "jane.doe@example.com", "Jane Doe");
var parameters = new[]
{
new PublicKeyCredentialParameters(COSEAlgorithmIdentifier.ES256),
new PublicKeyCredentialParameters(COSEAlgorithmIdentifier.RS256)
};
var selection = new AuthenticatorSelectionCriteria(AuthenticatorAttachment.Platform);
try
{
CredentialsResponse response = await WebAuthn.CreateAsync(
challenge, rp, user, parameters, selection, 60000, AttestationConveyancePreference.None);
// Store the credential with the user account.
PublicKey publicKey = response.AuthenticatorData.PublicKey;
SaveCredential(user.Id, publicKey.CredentialID, publicKey.ToJSON());
AlertBox.Show("Registration complete.");
}
catch (Exception ex)
{
AlertBox.Show("Registration failed: " + ex.Message, MessageBoxIcon.Error);
}
}
GetAsync(challenge, allowCredentials, timeout)
Gets the requested credentials from the client.
| Parameter | Type | Description |
|---|---|---|
| challenge | String | A base64-encoded random value generated by the server for validating the request. |
| allowCredentials | PublicKeyCredentialDescriptor[] | The credentials the server would like the user to authenticate with, or null to let the user choose a discoverable credential. |
| timeout | Int32 | The time in milliseconds that the user has to respond to the prompt. |
Returns: Task<CredentialsResponse>. A CredentialsResponse containing the signature, authenticator data, client data and user handle.
Pass the returned values to Validate together with the public key stored at registration to verify that the user owns the credential.
Throws:
- Exception The browser rejected the request, e.g. the user cancelled or the operation timed out.
Example:
private async void buttonLogin_Click(object sender, EventArgs e)
{
// Generate a random challenge, base64 encoded.
var bytes = new byte[32];
using (var rng = RandomNumberGenerator.Create())
rng.GetBytes(bytes);
string challenge = Convert.ToBase64String(bytes);
// Look up the credential registered for this user.
string userId = "user-1234";
var allowCredentials = new[] { new PublicKeyCredentialDescriptor(LoadCredentialID(userId)) };
CredentialsResponse response = await WebAuthn.GetAsync(challenge, allowCredentials, 60000);
var publicKey = new PublicKey(LoadPublicKeyJson(userId));
bool valid = WebAuthn.Validate(
publicKey,
response.AuthenticatorData.Base64,
response.ClientData.Base64,
response.Signature);
if (valid && response.AuthenticatorData.UserPresent)
AlertBox.Show("Welcome back!");
else
AlertBox.Show("Authentication failed.", MessageBoxIcon.Error);
}
IsUserVerifyingPlatformAuthenticatorAvailableAsync()
Checks whether the client device has a user-verifying platform authenticator available for use.
Returns: Task<Boolean>. True if the device has a user-verifying platform authenticator (e.g. Windows Hello, Touch ID or Face ID).
Example:
private async void Page1_Load(object sender, EventArgs e)
{
// Offer passkey registration only on devices that support it.
this.buttonRegister.Visible = await WebAuthn.IsUserVerifyingPlatformAuthenticatorAvailableAsync();
}
Validate(publicKey, authenticatorDataBase64, clientDataBase64, signature)
Validates the given assertion signature against the provided public key.
| Parameter | Type | Description |
|---|---|---|
| publicKey | PublicKey | The public key generated during registration. |
| authenticatorDataBase64 | String | The base64-encoded authenticator data, from Base64. |
| clientDataBase64 | String | The base64-encoded client data, from Base64. |
| signature | Byte[] | The authentication signature, from Signature. |
Returns: Boolean. True if the signature is valid; false if it is invalid or the key algorithm is not supported.
Supported algorithms are ES256 and RS256.
Throws:
- NotImplementedException The public key uses the EdDSA algorithm.
Example:
CredentialsResponse response = await WebAuthn.GetAsync(challenge, allowCredentials, 60000);
var publicKey = new PublicKey(LoadPublicKeyJson(userId));
bool valid = WebAuthn.Validate(
publicKey,
response.AuthenticatorData.Base64,
response.ClientData.Base64,
response.Signature);
if (!valid)
throw new UnauthorizedAccessException("Invalid WebAuthn signature.");