Skip to main content

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.

public static class WebAuthn

See https://w3c.github.io/webauthn/.

Methods​

Static member CreateAsync(challenge, rp, user, publicKeyCredentialParameters, authenticatorSelection, timeout, attestation)​

Creates new credentials for the client.

ParameterTypeDescription
challengeStringA base64-encoded random value generated by the server for validating the request.
rpRelyingPartyThe Relying Party (RP), the organization responsible for registering and authenticating the user.
userPublicKeyCredentialUserEntityInformation about the user currently registering.
publicKeyCredentialParametersPublicKeyCredentialParameters[]Array describing what public key types are acceptable to the server, in order of preference.
authenticatorSelectionAuthenticatorSelectionCriteriaRequirements for the authenticator, such as "platform" (Windows Hello) vs "cross-platform" (YubiKey).
timeoutInt32The time in milliseconds that the user has to respond to a prompt for registration.
attestationAttestationConveyancePreferenceIndicates 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);
}
}

Static member GetAsync(challenge, allowCredentials, timeout)​

Gets the requested credentials from the client.

ParameterTypeDescription
challengeStringA base64-encoded random value generated by the server for validating the request.
allowCredentialsPublicKeyCredentialDescriptor[]The credentials the server would like the user to authenticate with, or null to let the user choose a discoverable credential.
timeoutInt32The 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);
}

Static member 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();
}

Static member Validate(publicKey, authenticatorDataBase64, clientDataBase64, signature)​

Validates the given assertion signature against the provided public key.

ParameterTypeDescription
publicKeyPublicKeyThe public key generated during registration.
authenticatorDataBase64StringThe base64-encoded authenticator data, from Base64.
clientDataBase64StringThe base64-encoded client data, from Base64.
signatureByte[]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:

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.");