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.
4.0 KiB
← index · next: 02 — The minimum configuration
Versions, artifacts and the 7.0 split
The dependency the tutorials forget
Passkey support arrived in Spring Security 6.4, and at that time it lived inside
spring-security-web — which meant it was already on the classpath of every Spring
Boot application that used spring-boot-starter-security. As of Spring Security 7.0 it
does not. The classes were moved into a new artifact, spring-security-webauthn, which
spring-boot-starter-security does not pull in.
The move is visible in the jars:
$ unzip -l spring-security-web-6.5.11.jar | grep -c -i webauthn
135
$ unzip -l spring-security-web-7.1.1.jar | grep -i webauthn
10036 org/springframework/security/spring-security-webauthn.js
$ unzip -l spring-security-webauthn-7.1.1.jar | grep -c -i webauthn
139
The package names did not change — everything is still
org.springframework.security.web.webauthn.*. That is what makes the upgrade awkward: your
imports keep compiling against a stale local repository and fail on a clean build, and the
DSL method http.webAuthn(..) lives in spring-security-config, which is present either
way. Nothing tells you what is wrong except a ClassNotFoundException or a missing method.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-webauthn</artifactId>
</dependency>
No version: spring-boot-dependencies:4.1.1 manages it, at 7.1.1.
What did not move
Two things were left behind in spring-security-web:
| artefact | where it lives | why it matters |
|---|---|---|
spring-security-webauthn.js |
spring-security-web |
the browser-side script the default pages load |
user-credentials-schema.sql |
spring-security-web |
the DDL for JdbcUserCredentialRepository |
user-entities-schema.sql |
spring-security-web |
the DDL for JdbcPublicKeyCredentialUserEntityRepository |
spring-security-webauthn depends on spring-security-web, so all three are still reachable
— but a search inside the webauthn jar for the schema files the Javadoc points at comes
up empty, which is confusing the first time. See 09 — Persistence.
The versions this module was built and run against
| 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 |
| WebAuthn4J | 0.31.9.RELEASE |
| Jackson | 3.1.5 (tools.jackson) |
| Tomcat | 11.0.24 |
| H2 | 2.4.240 (jdbc profile only) |
| Maven | 3.9.11 |
Two details behind that table are worth keeping:
WebAuthn4J 0.31.9 is a Jackson 3 library. Its POM declares
tools.jackson.core:jackson-databind:3.2.1 and
tools.jackson.dataformat:jackson-dataformat-cbor:3.2.1. Spring Boot 4.1.1 manages Jackson at
3.1.5 and wins, so what actually resolves is jackson-dataformat-cbor-3.1.5.jar. Everything
in this module ran on that combination. If you are still on a Jackson 2 application, this is
a real constraint rather than a footnote.
spring-security-webauthn 7.0.7 and 7.1.1 contain exactly the same set of classes. A
class-by-class diff of the two jars is empty; only the pinned WebAuthn4J version moved, from
0.31.6 to 0.31.9. Nothing in this article is 7.1-specific in the way that, say,
csrf.spa() was 7.0-specific — it applies to the whole 7.x line, and mostly to 6.4 and
6.5 as well once you account for the artifact split.
What Spring Boot does not do
There is no WebAuthn auto-configuration, and there are no spring.security.webauthn.*
properties. Grepping spring-boot-autoconfigure-4.1.1.jar and spring-boot-security-4.1.1.jar
for webauthn returns nothing. Every relying party setting in this module is Java
configuration, because Java configuration is the only option.