@@ -275,7 +275,7 @@ First, generate authentication parameters and send them to the client:
275
275
[source,java]
276
276
----------
277
277
AssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()
278
- .username("alice") // Omit for username-less login
278
+ .username("alice")
279
279
.build());
280
280
String credentialGetJson = request.toCredentialGetJson();
281
281
return credentialGetJson; // Send to client
@@ -350,6 +350,71 @@ updateCredential( // Some database access method of your own design
350
350
Then do whatever else you need - for example, initiate a user session.
351
351
352
352
353
+ === Passwordless, username-less authentication
354
+
355
+ WebAuthn supports passwordless multi-factor authentication via on-authenticator
356
+ https://www.w3.org/TR/webauthn-2/#user-verification[user verification],
357
+ and username-less authentication via
358
+ https://www.w3.org/TR/webauthn-2/#discoverable-credential[discoverable credentials]
359
+ (sometimes the term "passwordless" is used to mean the combination of both, but
360
+ here the two are treated separately).
361
+
362
+ Discoverable credentials must be enabled at registration time by setting the
363
+ link:https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection[`authenticatorSelection`].link:https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey[`residentKey`]
364
+ option:
365
+
366
+ [source,java]
367
+ ----------
368
+ PublicKeyCredentialCreationOptions request = rp.startRegistration(
369
+ StartRegistrationOptions.builder()
370
+ .user(/* ... */)
371
+ .authenticatorSelection(AuthenticatorSelectionCriteria.builder()
372
+ .residentKey(ResidentKeyRequirement.REQUIRED)
373
+ .build())
374
+ .build());
375
+ ----------
376
+
377
+ The username can then be omitted when starting an authentication ceremony:
378
+
379
+ [source,java]
380
+ ----------
381
+ AssertionRequest request = rp.startAssertion(StartAssertionOptions.builder().build());
382
+ ----------
383
+
384
+ Some authenticators might enable this feature even if not required, and setting
385
+ the `residentKey` option to `ResidentKeyRequirement.PREFERRED` will enable it if the
386
+ authenticator supports it. The
387
+ https://www.w3.org/TR/webauthn-2/#sctn-authenticator-credential-properties-extension[`credProps` extension]
388
+ can be used to determine whether the created credential is discoverable, and is enabled by default.
389
+
390
+ User verification can be enforced independently per authentication ceremony:
391
+
392
+ [source,java]
393
+ ----------
394
+ AssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()
395
+ .username("alice")
396
+ .userVerification(UserVerificationRequirement.REQUIRED)
397
+ .build());
398
+ ----------
399
+
400
+ Then `RelyingParty.finishAssertion(...)` will enforce that user verification was
401
+ performed. However, there is no guarantee that the user's authenticator will
402
+ support this unless the user has some credential created with the
403
+ link:https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection[`authenticatorSelection`].link:https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification[`userVerification`]
404
+ option set:
405
+
406
+ [source,java]
407
+ ----------
408
+ PublicKeyCredentialCreationOptions request = rp.startRegistration(
409
+ StartRegistrationOptions.builder()
410
+ .user(/* ... */)
411
+ .authenticatorSelection(AuthenticatorSelectionCriteria.builder()
412
+ .userVerification(UserVerificationRequirement.REQUIRED)
413
+ .build())
414
+ .build());
415
+ ----------
416
+
417
+
353
418
== Architecture
354
419
355
420
The library tries to place as few requirements on the overall application
0 commit comments