Home

Awesome

Virtual WebAuthn

The Go package virtualwebauthn provides a set of helper tools for testing full WebAuthn authentication flows in a relying party WebAuthn server implementation without requiring a browser or an actual authenticator.

Check the test for a working example on how to use this library.

Features

Usage

Setup

First we create mock entities to work with for running tests.

// The relying party settings should mirror those on the actual WebAuthn server
rp := virtualwebauthn.RelyingParty{Name: "Example Corp", ID: "example.com", Origin: "https://example.com"}

// A mock authenticator that represents a security key or biometrics module
authenticator := virtualwebauthn.NewAuthenticator()

// Create a new credential that we'll try to register with the relying party
credential := virtualwebauthn.NewCredential(virtualwebauthn.KeyTypeEC2)

Register

Start a register flow with the relying party and get an attestationOptions JSON string that contains the serialized credential creation options:

// Ask the server to start a register flow for a user. The server and user here
// are placeholders for whatever the system being tested uses.
attestationOptions := server.registerStart(user)

Use the ParseAttestationOptions and CreateAttestationResponse functions to parse the attestationOptions string, ensure that it's valid, and generate an appropriate attestationResponse that should appear to have come from a browser's navigator.credentials.create call:

// Parses the attestation options we got from the relying party to ensure they're valid
parsedAttestationOptions, err := virtualwebauthn.ParseAttestationOptions(attestationOptions)
if err != nil {
    ...
}

// Creates an attestation response that we can send to the relying party as if it came from
// an actual browser and authenticator.
attestationResponse := virtualwebauthn.CreateAttestationResponse(rp, authenticator, credential, *parsedAttestationOptions)

We can now go back to the relying party with the attestationResponse and finish the register flow:

// Finish the register flow by sending the attestation response. Again the server and
// user here are placeholders for whatever the system being tested uses.
err := server.registerFinish(user, attestationResponse)
if err != nil {
    ...
}

// Add the EC2 credential to the mock authenticator
authenticator.AddCredential(credential)