A simple self-contained demo server supporting multiple authenticators per user. It illustrates how to use the required integration points, the most important of which is the user and credential registration storage, and also illustrates how one can perform auxiliary actions such as adding an additional authenticator or deregistering a credential.

The central part is the WebAuthnServer class, and the WebAuthnRestResource class which provides the REST API on top of it.

Quick start

./gradlew run
$BROWSER https://localhost:8443/

Or to run with the FIDO Metadata Service as a source of attestation metadata:

$BROWSER https://localhost:8443/


The example webapp is made up of three main layers, the bottom of which is the webauthn-server-core library:

  • The front end interacts with the server via a REST API, implemented in WebAuthnRestResource.

    This layer manages translation between JSON request/response payloads and domain objects, and most methods simply call into analogous methods in the server layer.

  • The REST API then delegates to the server layer, implemented in WebAuthnServer.

    This layer manages the general architecture of the system, and is where most business logic and integration code would go. The demo server implements the "persistent" storage of users and credential registrations - the CredentialRepository integration point - as the InMemoryRegistrationStorage class, which simply keeps them stored in memory for a limited time. The transient storage of pending challenges is also kept in memory, but for a shorter duration.

    The logic for authorizing registration of additional credentials, and deregistration of credentials, is also in this layer. In general, anything that would be specific to a particular Relying Party (RP) would go in this layer.

  • The server layer in turn calls the library layer, which is where the webauthn-server-core library gets involved. The entry point into the library is the RelyingParty class.

    This layer implements the Web Authentication Relying Party Operations, and takes care of all RP-agnostic parts of the Web Authentication logic: generating challenges and verifying all aspects of the responses. It is mostly stateless, and exposes integration points for storage of challenges and credentials. Some notable integration points are:


This subproject includes two ways to run the demo server:

  • As a .war archive to be deployed in any Java web server

  • As a standalone Java executable

.war archive

The .war archive includes a simple web GUI hosted at /, relative to the context root of the deployed .war application, which communicates with the server via a REST API served at /api/v1/.

To build it, run

../gradlew war

Standalone Java executable

The standalone Java executable has the main class demo.webauthn.EmbeddedServer. This server also serves the REST API at /api/v1/, and static resources for the GUI under /.

To build it, run one of the following:

../gradlew distTar
../gradlew distZip

This will build an archive which can be unpacked and run anywhere with a Java environment:

unzip webauthn-server-demo-$VERSION.zip
cd webauthn-server-demo-$VERSION
> ./bin/webauthn-server-demo.bat

To build and run the demo server via Gradle, run:

./gradlew run

This will serve the application under https://localhost:8443/.

Since WebAuthn requires a HTTPS connection, this demo server uses a dummy certificate. This will cause your browser to show a warning, which is safe to bypass. The dummy certificate is not included in the .war artifact; it is only used by the embedded Jetty server and the application distribution archives.


Both modes of running the server accept the following environment variables for configuration. Note that if running via Gradle, you may need to disable the Gradle daemon (--no-daemon) in order for the server process to have the correct environment.

  • YUBICO_WEBAUTHN_PORT: Port number to run the server on. Example: YUBICO_WEBAUTHN_PORT=8081

    This is ignored when running as a .war artifact, since the port is controlled by the parent web server.

  • YUBICO_WEBAUTHN_ALLOWED_ORIGINS: Comma-separated list of origins the server will accept requests from. Example: YUBICO_WEBAUTHN_ALLOWED_ORIGINS=http://demo.yubico.com:8080

  • YUBICO_WEBAUTHN_RP_ID: The RP ID the server will report. Example: YUBICO_WEBAUTHN_RP_ID=demo.yubico.com

  • YUBICO_WEBAUTHN_RP_NAME: The human-readable RP name the server will report. Example: YUBICO_WEBAUTHN_RP_NAME='Yubico Web Authentication demo'

  • YUBICO_WEBAUTHN_USE_FIDO_MDS: If set to true (case-insensitive), use FidoMetadataService from the webauthn-server-attestation module as a source of attestation data in addition to the static JSON file bundled with the demo. This will write cache files to the webauthn-server-demo project root directory; see the patterns in the .gitignore file.