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.
39 lines
2.5 KiB
Plaintext
39 lines
2.5 KiB
Plaintext
==============================================================================
|
|
JDBC persistence - H2, with Spring Security's own schema
|
|
==============================================================================
|
|
schema-locations point at classpath:org/springframework/security/user-entities-schema.sql
|
|
and user-credentials-schema.sql, which live in spring-security-web, not in
|
|
spring-security-webauthn. Nothing creates these tables for you.
|
|
|
|
|
|
=== Registration ceremony, then authentication ceremony, no browser involved ===
|
|
POST /login (password) -> HTTP 302, Location: http://localhost:8080/
|
|
|
|
$ POST /webauthn/register/options
|
|
HTTP 200
|
|
{"attestation":"none","authenticatorSelection":{"residentKey":"required","userVerification":"preferred"},"challenge":"hahNpzhow1MxVRCiR8XSlgtl-C7u0a0jsv6J3REL-A8","excludeCredentials":[],"extensions":{"credProps":true},"pubKeyCredParams":[{"alg":-8,"type":"public-key"},{"alg":-7,"type":"public-key"},{"alg":-257,"type":"public-key"}],"rp":{"id":"localhost","name":"ankurm passkeys demo"},"timeout":300000,"user":{"name":"user","id":"hfu2DnARNIH5VbqLz2F0gBR93S2Z9o2MmCakwWCgAgM","displayName":"user"}}
|
|
authenticator produced credentialId Pp2xpfO7m1rnhV0cqUDvvA and a 178-byte CBOR attestation object
|
|
|
|
$ POST /webauthn/register
|
|
HTTP 200
|
|
{"success":true}
|
|
|
|
$ GET /diag/credentials
|
|
HTTP 200
|
|
{"principal":"user","principalType":"UsernamePasswordAuthenticationToken","authorities":["FactorGrantedAuthority [authority=FACTOR_PASSWORD, issuedAt=2026-08-25T17:21:25.201127080Z]","ROLE_USER"],"userEntity":{"name":"user","displayName":"user","id":"hfu2DnARNIH5VbqLz2F0gBR93S2Z9o2MmCakwWCgAgM"},"credentials":[{"label":"yubikey-on-my-desk","credentialId":"Pp2xpfO7m1rnhV0cqUDvvA","signatureCount":0,"uvInitialized":true,"backupEligible":true,"backupState":true,"transports":["hybrid","internal"],"attestationObjectBytes":178,"created":"2026-08-25T17:21:25.819064Z","lastUsed":"2026-08-25T17:21:25.819064Z"}]}
|
|
logged out, cookie jar emptied
|
|
|
|
=== Session dropped. Authenticating with the passkey alone ===
|
|
|
|
$ POST /webauthn/authenticate/options
|
|
HTTP 200
|
|
{"allowCredentials":[],"challenge":"zS7lWt58FceogQ7sg7Uj6vfBOVgLafRlEeGpq5WZIjg","extensions":{},"rpId":"localhost","timeout":300000,"userVerification":"preferred"}
|
|
|
|
$ POST /login/webauthn
|
|
HTTP 200
|
|
{"authenticated":true,"redirectUrl":"/"}
|
|
|
|
$ GET /me
|
|
HTTP 200
|
|
{"name":"user","authenticationType":"WebAuthnAuthentication","authorities":["FactorGrantedAuthority [authority=FACTOR_WEBAUTHN, issuedAt=2026-08-25T17:21:26.157551281Z]","ROLE_USER"]}
|