Class WebAuthnConfigurer
Passkeys: a user who is signed in registers one, and from then on signs in with it.
http.formLogin(Customizer.withDefaults())
.webAuthn(passkeys -> passkeys
.rpId("example.com")
.rpName("Example")
.allowedOrigins("https://example.com"));
The relying party id is the domain the passkeys belong to, and the allowed
origins are where the ceremonies may run -- each exactly as a client
reports it, compared whole. An Android application reports
android:apk-key-hash: and the base64url SHA-256 of its signing
certificate; list it beside the web origin when the application is to use
the same passkeys.
The endpoints
They take and answer JSON, the forms the WebAuthn specification defines,
so a browser's PublicKeyCredential.parseCreationOptionsFromJSON /
parseRequestOptionsFromJSON / toJSON() and the Codename One client's
WebAuthnClient work with them as they are. No page is served: the
application has its own, or is an app.
| Request | Who | Does |
|---|---|---|
POST /webauthn/register/options |
signed in | answers the options to make a passkey with |
POST /webauthn/register |
signed in | takes the authenticator's answer; {"success":true,"credentialId":"..."}, or 400 and {"success":false,"error":"..."} |
DELETE /webauthn/register/{credentialId} |
signed in, the owner | removes a passkey; 204, or 404 |
POST /webauthn/authenticate/options |
anybody | answers the options to sign in with |
POST /login/webauthn |
anybody | takes the authenticator's answer and signs the user in; {"authenticated":true,"redirectUrl":"/"}, or 401 and {"authenticated":false} |
POST /webauthn/register takes the credential as the client has it, with
an optional label beside it or as a query parameter, or wrapped as Spring
Security wraps it: {"publicKey": {"credential": {...}, "label": "..."}}.
A ceremony's options wait in the session they were asked from, for five minutes, and are taken out before the answer is looked at, so a challenge is answered once. "Signed in" means in this session: somebody a remember-me cookie brought back is asked to sign in before they may add or remove a passkey.
A refused sign-in is answered 401 and nothing more; which check refused it
is in the WebAuthnException the
failureHandler is given, for the server's log.
A second factor
A passkey whose authenticator verified the user -- a fingerprint, a face,
a PIN -- is two factors in one step, and signs the user in without the
chain's mfa() asking for a code. One that did not verify the user is one
factor, as a password is, and the second factor is then asked for as it
is after a password. To have every passkey sign-in be the first kind, call
userVerification("required").
CSRF
On a chain that keeps a session the two sign-in requests and the three
registration requests are checked for the CSRF token like any other
POST and DELETE. A page sends it as it does for its other requests. An
app, which has no page to read it from, is served by a chain that leaves
the ceremony out of the check:
http.csrf(csrf -> csrf.ignoringRequestMatchers("/webauthn/**", "/login/webauthn"));
The four POSTs lose little by it: each answers, or is answered by, a
challenge that is 32 random bytes kept in the caller's own session, which
a page of another site can neither read nor guess. DELETE has no such
thing; leave it under the check where browsers sign in to the same chain.
Where things come from
Passkeys are kept in the application's
UserCredentialRepository bean and its
PublicKeyCredentialUserEntityRepository bean -- in the database with the
Jdbc implementation of each -- or in the ones given here. With neither
they are kept in memory and are gone when the server stops, which a server
outside a development profile says once when it starts. A user who signs
in is looked up in the application's UserDetailsService, for their
authorities and for whether they may sign in at all.
-
Method Summary
Modifier and TypeMethodDescriptionallowCrossOrigin(boolean allow) Whether a ceremony may run in a frame of another origin.allowedOrigins(String... origins) The origins a ceremony may run on:https://example.com, with a port when it is not the default and nothing after it; andandroid:apk-key-hash:...for an Android application.allowUnverifiedAttestation(boolean allow) Whether a registration whose attestation this server cannot verify is accepted as if it carried none; seeWebAuthnRelyingPartyOperations.setAllowUnverifiedAttestation(boolean).authenticatorAttachment(String authenticatorAttachment) platformfor the device's own authenticator,cross-platformfor a security key, null -- the default -- for either.challengeValiditySeconds(int seconds) How long a ceremony's options wait for their answer; 300 seconds unless set.The clock a challenge's lifetime is read from; for tests.voidconfigure(HttpSecurity http) Adds this part's filters; nothing by default.defaultSuccessUrl(String defaultSuccessUrl) TheredirectUrla sign-in is answered with when no page asked for it.failureHandler(AuthenticationFailureHandler failureHandler) Answers a refused sign-in itself, instead of the 401; it is handed the exception, which says why.voidinit(HttpSecurity http) Shares what other parts need to know; nothing by default.relyingPartyOperations(WebAuthnRelyingPartyOperations operations) The ceremonies themselves, made by the application: everything set here about the relying party and the repositories is then its.residentKey(String residentKey) Whether a new credential must be one a sign-in can find without being told the user:required-- the default --preferredordiscouraged.The relying party id: the domain passkeys are bound to, such asexample.com.What the user is shown as the site's name; the id unless set.What is told of a signature counter that did not advance: a credential that may have been copied.successHandler(AuthenticationSuccessHandler successHandler) Answers a sign-in itself, instead of the JSON.userCredentialRepository(UserCredentialRepository repository) Where credentials are kept, in place of the application's bean.userDetailsService(UserDetailsService userDetailsService) The users a passkey signs in, in place of the application's bean.Where users' handles are kept, in place of the application's bean.usernameFirst(boolean usernameFirst) WhetherPOST /webauthn/authenticate/optionsmay be told ausernameuserVerification(String userVerification) Whether the authenticator must verify the user:required,preferred-- the default -- ordiscouraged.Methods inherited from class SecurityConfigurer
disable, getBuilder
-
Method Details
-
rpId
The relying party id: the domain passkeys are bound to, such asexample.com. Required. -
rpName
What the user is shown as the site's name; the id unless set. -
allowedOrigins
The origins a ceremony may run on:https://example.com, with a port when it is not the default and nothing after it; andandroid:apk-key-hash:...for an Android application. Required. -
userVerification
Whether the authenticator must verify the user:required,preferred-- the default -- ordiscouraged. See the class for what it means for a second factor. -
residentKey
Whether a new credential must be one a sign-in can find without being told the user:required-- the default --preferredordiscouraged. -
authenticatorAttachment
platformfor the device's own authenticator,cross-platformfor a security key, null -- the default -- for either. -
allowUnverifiedAttestation
Whether a registration whose attestation this server cannot verify is accepted as if it carried none; seeWebAuthnRelyingPartyOperations.setAllowUnverifiedAttestation(boolean). Off unless set, and such a registration is refused with a message naming the format. -
allowCrossOrigin
Whether a ceremony may run in a frame of another origin. Off unless set. -
usernameFirst
WhetherPOST /webauthn/authenticate/optionsmay be told ausername-- in a JSON body or as a parameter -- and then lists that user's credentials, so that a security key which holds no discoverable credential can answer. Off unless set, because the list tells whoever asks that the user exists and has passkeys; a passkey needs no name. -
challengeValiditySeconds
How long a ceremony's options wait for their answer; 300 seconds unless set. -
userCredentialRepository
Where credentials are kept, in place of the application's bean. -
userEntityRepository
Where users' handles are kept, in place of the application's bean. -
userDetailsService
The users a passkey signs in, in place of the application's bean. -
relyingPartyOperations
The ceremonies themselves, made by the application: everything set here about the relying party and the repositories is then its. -
signatureCounterListener
public WebAuthnConfigurer signatureCounterListener(WebAuthnRelyingPartyOperations.SignatureCounterListener listener) What is told of a signature counter that did not advance: a credential that may have been copied. The sign-in is refused either way. -
defaultSuccessUrl
TheredirectUrla sign-in is answered with when no page asked for it. -
successHandler
Answers a sign-in itself, instead of the JSON. -
failureHandler
Answers a refused sign-in itself, instead of the 401; it is handed the exception, which says why. -
clock
The clock a challenge's lifetime is read from; for tests. -
init
Description copied from class:SecurityConfigurerShares what other parts need to know; nothing by default.- Overrides:
initin classSecurityConfigurer
-
configure
Description copied from class:SecurityConfigurerAdds this part's filters; nothing by default.- Overrides:
configurein classSecurityConfigurer
-