ASP.NET Core 5.0 - Users Without Passwords

This article introduces a series about the implementation WebAuthn, also known as FIDO2, instead of passwords. The user registers with a FIDO2 authenticator like a usb security key or Windows Hello. I will assume you have downloaded the ASP.NET Core 5.0 - Users Without Passwords Project.

Users Without Passwords Project and Article Series

I have developed two separate projects in the Users Without Passwords Project (UWPP) solution. The Users Without Passwords v4 project supports Bootstrap v4 and the new Users Without Passwords project supports Bootstrap v5. The new version is published at Fido.KenHaggerty.Com. You can register a new user with Windows Hello or a FIDO2 security key. Details, screenshots, and related articles can be found at ASP.NET Core 5.0 - Users Without Passwords Project. The details page includes the version change log.

FIDO (Fast IDentification Online) UAF (Universal Authentication Framework) supports a passwordless experience. With FIDO UAF, the user carries a device with a FIDO UAF stack installed. They can then register their device to the online service by selecting a local authentication mechanism such as swiping a finger, looking at the camera, speaking into the mic, entering a PIN, etc. The FIDO UAF protocol allows the service to select which mechanisms are presented to the user.

Modern browsers support WebAuthn but you should verify support for credentials. See Can I Use Web Authentication API. I detect support with a global JavaScript function in site.js.

function detectWebAuthnSupport() {
    if (!('credentials' in navigator)) return 'This browser does not currently support Credentials.';
    if (window.PublicKeyCredential === undefined || typeof window.PublicKeyCredential !== 'function') {
        let errorMessage = 'This browser does not currently support WebAuthn.';
        if (window.location.protocol === 'http:' &&
            (window.location.hostname !== 'localhost' && window.location.hostname !== ''))
            errorMessage = 'WebAuthn only supports secure connections. ' +
                'For testing over HTTP, you can use the origin \"localhost\".';
        return errorMessage;
    return '';

I developed a message modal which can be configured with no dismiss button, a redirect link, a 'static' backdrop and keyboard=false. See ASP.NET Core 3.1 - Message Modal.

let webAuthnError = detectWebAuthnSupport();
if (webAuthnError != '') {
    showMessageModal(webAuthnError, 'alert-danger', false, '', '', true, '/', '_self', 'Home');
WebAuthn Not Supported.
WebAuthn Not Supported Mobile.
Project Evolution

I have been researching this project for over a year. When I started, I just wanted to register a user and then login with a device. With the help of GitHub - scottbrady91/Fido2-Poc and my first yubico security key, I developed an ASP.NET Core 3.1 Razor Pages project which registered and authenticated a user without a password.

My next objective was to implement multiple credentials and credential management per user. At the time, my second FIDO2 device was Windows Hello. The yubico security key uses Elliptic Curve cryptography and Windows Hello uses RSA cryptography. With the help of GitHub - abergs/fido2-net-lib, I implemented RSA cryptography. Then I implemented ExcludedCredentials and AllowCredentials with CredentialOptions to support multiple credentials.

After I purchased a HyperFIDO Titanium PRO key and a second yubico key, I started tracking the device's AAGUID which stands for “Authenticator Attestation Globally Unique ID”. I had issues trying to store and verify the signature counter. The signature counter should increment with each authentication. I published that version of the project to and emailed HyperFIDO support including the AAGUID asking for help. The kind folks at Hypersceu analyzed the published project and replied letting me know I was not decoding big-endian values properly. Even the AAGUID which is big-endian didn't match. I was embarrassed but thankful I had not released that version.

I developed attestation and assertion crypto classes and commented the code with references to the new standards published by the World Wide Web Consortium. See Web Authentication: An API for accessing Public Key Credentials Level 2 W3C Proposed Recommendation, 25 February 2021. The UWPP verifies all the new standards except MetadataService lookup (7.1.20) and TokenBinding (7.1.10, 7.2.14) which is not supported by popular browsers. The project verifies the "packed" and "tpm" (Trusted Platform Module) attestation formats. The project implements the MSDocs - AsnDecoder Class, new in .NET 5.0, to help verify the Attestation x5c certificate chain. If the verification for a standard fails, an invalid challenge with the error message is logged. Valid challenges are logged when a challenge completes successfully. The user can display the challenge history by credential in Manage > Credentials.

Challenge History By Credential.
Challenge History By Credential Mobile.

I developed a user administration panel. Administrators can display and edit credentials per user, list challenges per credential, and list invalid challenges. I imagined a use case where an administrator creates a new user with a dedicated device. Then delivers the device to the user before they can log in.

Admin New Admin.
Admin New Admin Mobile.
Admin New Admin Challenge.
Admin New Admin Challenge Mobile.

All my projects get their biggest revision when I start to write and organize the related articles. Often, when I start to explain a process or method in an article, I refactor the code to make it more self-explanatory. WebAuthn is a complex specification and I am still researching and learning. The article series will present the tasks I used to implement WebAuthn in the Users Without Passwords Project (UWPP).


One of the first tasks was creating the challenge code which is required by the authenticating device. It is created on the server and is used to verify the response from the authenticator. The challenge code must persist on the server between requests. I published ASP.NET Core 3.1 - Round Trip Challenge almost a year ago. This article will review the process and add a couple of enhancements.

Challenge Options

There are CredentialCreationOptions and CredentialRequestOptions. Options like ExcludedCredentials and AllowCredentials are dynamic, but most are static. I load a few default options from appsettings.json for custom configurations. CredentialOptions have strict rules for names and structures. The UWPP employs System. Text. Json rather than Newtonsoft. Json. I developed option classes with appropriate properties and serialize with camel case JsonSerializerOptions.

var jsonSerializerOptions = new JsonSerializerOptions
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
    WriteIndented = true
Credential Devices

I have 2 yubico keys with NFC (Security Key NFC), a HyperFIDO Titanium PRO and a HyperFIDO PRO MINI. My laptop has a fingerprint scanner which works with Windows Hello. I even bought an IR webcam to test facial recognition. Probably my most useful device is a male micro USB to female USB adapter because my phone doesn't have NFC.

Windows Hello implements authentication with an IR webcam for facial recognition, a fingerprint scanner, or just by setting up and using a PIN. See Learn about Windows Hello and set it up.

Credential Create

The registration or attestation ceremony requires a valid decoded response from the authenticating device before the user and a related credential are created. The UWPP detects platform authenticators like Windows Hello with the PublicKeyCredential. isUserVerifying PlatformAuthenticatorAvailable JavaScript function. The main purpose of the authenticator's response is to provide a Credential Id and a PublicKey which are used to configure an authentication request and validate the response from a log in or assertion ceremony. The UWPP configures the CredentialCreationOptions before the user calls the navigator. credentials. create() function from JavaScript.

Credential Get

The log in or assertion ceremony verifies the authenticating device belongs to the user and validates the integrity of the response with the PublicKey and the response signature. The UWPP configures the CredentialRequestOptions including a list of AllowCredentials which are all the Credential Ids related to the user before the user calls the navigator. credentials. get() function from JavaScript.

Attestation Trust

The Attestation option in CredentialCreationOptions defaults to "none". See Attestation Conveyance Preference Enumeration. This configuration indicates that the Relying Party is not interested in authenticator attestation. I needed to override this option when I wanted to track the device's AAGUID. When the Attestation option is configured, the response includes an AttestationObject which is used to prove the trustworthiness of the device. The AttestationObject contains a attestation trust path, chain of X.509 certificates, with the "packed" and "tpm" Attestation Statement formats. The UWPP validates the trust path for the "packed" and "tpm" formats. See Defined Attestation Statement Formats.

Multiple Credentials

The UWPP implements AllowCredentials and ExcludedCredentials. AllowCredentials, the list of credential Ids related to a user, is used by the log in or assertion ceremony. When the user adds new credentials, the ExcludedCredentials list is used by the attestation ceremony and excludes known authenticators. The UWPP implements credential management with a primary credential and editable credential name.

Manage Multiple Credentials.
Manage Multiple Credentials Mobile.
Ken Haggerty
Created 04/09/21
Updated 08/16/21 03:59 GMT

Log In or Reset Quota to read more.

Successfully completed. Thank you for contributing.
Contribute to enjoy content without advertisments.
Something went wrong. Please try again.



Not accepting new comments.

Submit your comment. Comments are moderated.

User Image.
DisplayedName - Member Since ?