Demo: passkey (WebAuthn) login
Location: contrib/demo/passkey/
Starts a single ahdapa instance configured for WebAuthn passkey authentication using static users — no FreeIPA or Kerberos infrastructure is required. On first run only password login is available; a registration helper page lets you create a passkey credential and add it to the users file.
What it shows
- WebAuthn credential registration — a standalone HTML page served by the
demo instance walks through the
navigator.credentials.create()call and generates thepasskey:<credentialId>,<COSE_Key>line for the users file. - Passkey login — after adding the credential to the overlay file, entering
a username on the login page triggers the
navigator.credentials.get()prompt instead of (or before) the password field. - Overlay-based credential management — a gitignored overlay file is merged
with the base users file at startup. The overlay takes precedence over same-
username entries in the base file, so passkey credentials can be added without
modifying the tracked
users.toml. - RP ID scoping — the demo uses RP ID
localhost. Passkeys registered with this configuration are tied tolocalhostand will not work on any other origin.
Prerequisites
ahdapabinary — the script looks in$PATHfirst (resolved to its full path), thentarget/release/ahdapa, thentarget/debug/ahdapa, and falls back tocargo buildif none is found.npm— for building the WebUIdist/directory on first run.- A browser that supports WebAuthn (all modern browsers do).
- Port 8080 free.
- For hardware security key testing: a FIDO2-capable key (YubiKey, SoloKey, etc.)
- For virtual authenticator testing: Chrome DevTools → Application → Web Authentication → Enable virtual authenticator.
Running
contrib/demo/passkey/run.sh
On first run (when no webui/dist/ directory and no pre-built binary exist)
the script builds the WebUI and the binary, then starts ahdapa. If a binary
is already installed or built, it is used directly and the build step is
skipped. The selected binary path is printed before launch:
==> Building WebUI (first run)…
Using binary: /home/user/ahdapa/target/release/ahdapa
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PASSKEY DEMO
Server → http://localhost:8080
WebUI → http://localhost:8080/ui/
OIDC discovery → http://localhost:8080/.well-known/openid-configuration
Register page → http://localhost:8080/ui/passkey-register.html
Password logins:
alice / alice123 (admins, editors)
bob / bob123 (editors)
carol / carol123
Passkey login: no
RP ID: localhost
DB: /tmp/ahdapa-passkey-demo.db (delete to reset)
Press Ctrl-C to stop.
Enabling passkey login
Step 1 — start the demo
contrib/demo/passkey/run.sh
Step 2 — register a passkey for alice
Open http://localhost:8080/ui/passkey-register.html in a browser. Enter
alice and click Register passkey. The browser prompts for authentication
via platform authenticator, a hardware key, or a virtual authenticator in
DevTools.
After the ceremony completes, the page displays a line in the form:
passkey:<base64-credentialId>,<base64-COSE_Key>
Copy this line.
Step 3 — create the overlay file
cp contrib/demo/passkey/users.passkeys.toml.example \
contrib/demo/passkey/users.passkeys.toml
Edit users.passkeys.toml and paste the copied line into alice’s passkeys
array. Ensure the password field is also present so password login continues
to work:
[[user]]
username = "alice"
password = "alice123"
name = "Alice Admin"
given_name = "Alice"
family_name = "Admin"
email = "alice@dev.local"
groups = ["admins", "editors"]
passkeys = [
"passkey:AAAA...base64...,BBBB...base64...",
]
Step 4 — restart the demo
Stop the running server (Ctrl-C), then:
contrib/demo/passkey/run.sh
The startup output now shows Passkey login: yes (alice). On the login page,
entering alice triggers the passkey prompt from the browser instead of the
password field.
Configuration notes
| File | Description |
|---|---|
ahdapa.toml | Server config with passkey_rp_id = "localhost" and GSSAPI disabled |
users.toml | Base users file (alice, bob, carol) with password login only |
users.passkeys.toml.example | Template for the passkey overlay; copy and fill in credential |
users.passkeys.toml | Your local overlay (gitignored); merged with users.toml at startup |
passkey-register.html | Registration helper page; served from webui/dist/ |
run.sh | Build and launch script |
The run.sh script merges the overlay and base files before starting:
# If overlay exists, prepend it (overlay entries take precedence).
cat users.passkeys.toml users.toml > /tmp/ahdapa-passkey-demo-users.toml
The merged file path is set in ahdapa.toml:
[users]
file = "/tmp/ahdapa-passkey-demo-users.toml"
RP ID
The passkey_rp_id must match the origin of the page that registered the
credential. For localhost development it is always "localhost". For a
production FreeIPA deployment, set it to the IPA domain name (e.g.
"ipa.example.com"), which is also what FreeIPA uses when managing passkeys
via ipa user-add-passkey.
[ipa]
passkey_rp_id = "localhost"
Resetting
Delete the demo database to discard all CRDT state (OAuth2 clients, keys) and start fresh:
rm /tmp/ahdapa-passkey-demo.db
The passkey credential registered in the browser is separate from the database: it is stored in the operating system’s credential store or on the hardware key. You can re-register any time using the registration page.
See also
- Authentication Methods — passkey and WebAuthn configuration reference.
- FreeIPA Co-deployment — passkey management
integrated with FreeIPA
ipa user-add-passkey.