1
0
Files
spring-auth-demo/docs/passkeys/README.md
Ankur Mhatre f6dd692177 Add passkeys project: WebAuthn ceremonies, a software authenticator and the one-time-token fallback
Fourth Maven project in the repository. Registration and authentication run end to
end with no browser and no hardware key: VirtualAuthenticator emits real CBOR
attestation objects and real ES256 assertion signatures, and tools/PasskeyCeremony.java
drives the live HTTP endpoints with them.

Profiles cover userVerification REQUIRED, DIRECT attestation, a disallowed origin and
JDBC persistence. Eleven doc chapters and twelve captured transcripts under docs/passkeys
and docs/output/pk-*.txt, all regenerated by passkeys/scripts/run-all.sh.
2026-08-25 23:00:27 +05:30

4.4 KiB

Passkeys and WebAuthn with Spring Security 7.1

Companion documentation for Passkeys and WebAuthn with Spring Security 7 on ankurm.com, and for the code in passkeys/.

The other three projects in this repository move bearer tokens around. This one gets rid of the password — and then spends most of its length on the parts that are not the ceremony, because the ceremony is the easy half.

Everything here was run. There is no browser and no hardware key anywhere in this module: a software authenticator produces genuine CBOR attestation objects and genuine ES256 assertion signatures, and Spring Security verifies them without noticing.

JDK Temurin 25.0.4.1+1 (current LTS)
Spring Boot 4.1.1
Spring Framework 7.0.9
Spring Security 7.1.1 (GA 20 August 2026)
spring-security-webauthn 7.1.1 — a separate artifact since 7.0
WebAuthn4J 0.31.9.RELEASE
Jackson 3.1.5 (tools.jackson)
Tomcat 11.0.24
Maven 3.9.11

Every file in docs/output/pk-*.txt is real program output, regenerated by passkeys/scripts/run-all.sh.

Chapters

# chapter what it settles
01 Versions, artifacts and the 7.0 split the dependency spring-boot-starter-security does not give you
02 The minimum configuration six endpoints from one DSL block, and the bean that silently disables it
03 The two ceremonies what is on the wire, and what every default in the options object means
04 A software authenticator how to execute a passkey ceremony in CI, with no browser
05 The defaults user verification is optional, and asking for attestation is not checking it
06 The bootstrap problem a passkey cannot be a user's first credential
07 Failure modes why every registration failure is a 500 and every login failure is a bare 401
08 The one-time-token fallback the way in, the way back, and the rate limit that does not exist
09 Persistence the in-memory default, the missing DDL, and the column you must not drop
10 The signature counter stored on every login, compared against on none
11 Should you build this the honest answer, and what the afternoon actually costs

Captured output

file produced by shows
pk-ceremony.txt scripts/ceremony.sh registration and authentication, end to end
pk-counter.txt scripts/counter.sh a stale signature counter being accepted
pk-user-verification.txt scripts/user-verification.sh preferred versus required, same authenticator
pk-origin.txt scripts/origin.sh the phishing defence, in both ceremonies
pk-attestation.txt scripts/attestation.sh direct requested, none accepted
pk-duplicate.txt scripts/duplicate.sh excludeCredentials, and a client that ignores it
pk-bootstrap.txt scripts/bootstrap.sh registration options with nobody logged in
pk-step-up.txt scripts/step-up.sh FACTOR_WEBAUTHN versus FACTOR_OTT on one endpoint
pk-ott.txt scripts/ott-fallback.sh generate, redeem, and redeem again
pk-jdbc.txt scripts/jdbc.sh the same ceremony against H2
pk-filters.txt scripts/filters.sh the live filter chain, all 25 of it
pk-test-run.txt scripts/test-run.sh seven contract tests

Quickstart

cd spring-auth-demo/passkeys
./scripts/run.sh                 # http://localhost:8080/login, user/password
./scripts/ceremony.sh            # both ceremonies, no browser
./scripts/run-all.sh             # regenerate every docs/output/pk-*.txt