Spring Security provides support for https://www.passkeys.com[passkeys].
Passkeys are a more secure method of authenticating than passwords and are built using https://www.w3.org/TR/webauthn-3/[WebAuthn].
In order to use a passkey to authenticate, a user must first xref:servlet/authentication/passkeys.adoc#passkeys-register[Register a New Credential].
After the credential is registered, it can be used to authenticate by xref:servlet/authentication/passkeys.adoc#passkeys-verify[verifying an authentication assertion].
To get started, add the `webauthn4j-core` dependency to your project.
[NOTE]
====
This assumes that you are managing Spring Security's versions with Spring Boot or Spring Security's BOM as described in xref:getting-spring-security.adoc[].
The following configuration enables passkey authentication.
It provides a way to xref:./passkeys.adoc#passkeys-register[] at `/webauthn/register` and a default log in page that allows xref:./passkeys.adoc#passkeys-verify[authenticating with passkeys].
WebAuthn performs persistence with javadoc:org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository[] and javadoc:org.springframework.security.web.webauthn.management.UserCredentialRepository[].
The default is to use in memory persistence, but JDBC persistence is support with javadoc:org.springframework.security.web.webauthn.management.JdbcPublicKeyCredentialUserEntityRepository[] and javadoc:org.springframework.security.web.webauthn.management.JdbcUserCredentialRepository[].
To configure JDBC based persistence, expose the repositories as a Bean:
fun jdbcUserCredentialRepository(jdbc: JdbcOperations): JdbcUserCredentialRepository {
return JdbcUserCredentialRepository(jdbc)
}
----
======
If JDBC does not meet your needs, you can create your own implementations of the interfaces and use them by exposing them as a Bean similar to the example above.
The `PublicKeyCredentialCreationOptionsRepository` is used to persist the `PublicKeyCredentialCreationOptions` between requests.
The default is to persist it the `HttpSession`, but at times users may need to customize this behavior.
This can be done by setting the optional property `creationOptionsRepository` demonstrated in xref:./passkeys.adoc#passkeys-configuration[Configuration] or by exposing a `PublicKeyCredentialCreationOptionsRepository` Bean:
After the registration options are obtained, they are used to create the credentials that are registered.
To register a new credential, the application should pass the options to https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create[`navigator.credentials.create`] after base64url decoding the binary values such as `user.id`, `challenge`, and `excludeCredentials[].id`.
The returned value can then be sent to the server as a JSON request.
An example registration request can be found below:
<1> The result of calling `navigator.credentials.create` with binary values base64url encoded.
<2> A label that the user selects to have associated with this credential to help the user distinguish the credential.
.Example Successful Registration Response
[source,http]
----
HTTP/1.1 200 OK
{
"success": true
}
----
[[passkeys-verify]]
== Verifying an Authentication Assertion
After xref:./passkeys.adoc#passkeys-register[] the passkey can be https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion[verified] (authenticated).
Verifying a credential is composed of two steps:
1. Requesting the Verification Options
2. Verifying the Credential
[[passkeys-verify-options]]
=== Request the Verification Options
The first step in verification of a credential is to request the verification options.
In Spring Security, a request for the verification options is typically done using JavaScript and looks like:
[NOTE]
====
Spring Security provides a default log in page that can be used as a reference on how to verify credentials.
After the verification options are obtained, they are used to get a credential.
To get a credential, the application should pass the options to https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create[`navigator.credentials.get`] after base64url decoding the binary values such as `challenge`.
The returned value of `navigator.credentials.get` can then be sent to the server as a JSON request.
Binary values such as `rawId` and `response.*` must be base64url encoded.
An example authentication request can be found below: