WebauthnComponents.RegistrationComponent (WebauthnComponents v0.11.3)

View Source

LiveComponent for creating a new Webauthn credential for a user.

This component may be used when signing up a new user or adding a new Passkey for an existing user.

Assigns

  • @id (Required) An HTML element ID.
  • @public_key_options (Required) A WebauthnComponents.PublicKeyCredentialCreationOptions struct describing the credential to create.
  • @trusted_attestation_types (Optional) Attestation types accepted by the server. Defaults to [:none, :basic]. See Wax.Attestation.type/0 for possible values.
  • @disabled (Optional) Disables the button. Defaults to false.
  • @class (Optional) CSS classes for the button.
  • @rest (Optional) Additional HTML attributes for the button.

Messages

  • %Wax.AuthenticatorData{} — the credential was created. Persist the attested credential data (see above).
  • {:error, payload} — a client-side error. payload contains the message, name, and stack reported by the browser.
  • A Wax error struct (for example, %Wax.InvalidCBORError{} or %Wax.ExpiredChallengeError{}) — server-side verification failed.

Credential Persistence

Once a credential has been successfully created, this component will send a Wax.AuthenticatorData.t/0 message to the parent LiveView. This struct contains data required to authenticate the user on subsequent visits, as well as some metadata from the authenticator device.

Minimum Persistence

At a minimum, the :id and :public_key values must be persisted along with the :user_id (or appropriate foreign key).

During future authentication attempts, the WebauthnComponents.AuthenticationComponent will send a WebauthnComponents.FindUser.t/0 struct, which includes a :user_handle the server must use to locate the user.

See WebauthnComponents.User.t/0 for details.

The following example illustrates how a user and credential may be registered (some details omitted):

# some_live_view.ex
def handle_info(%Wax.AuthenticatorData{} = auth_data, socket) do
  %{form: form} = socket.assigns
  
  with {:ok, user} <- MyApp.Identity.register_user(form.source),
      {:ok, credential} <- MyApp.Identity.register_credential(user, auth_data) do
      {
        :noreply,
        socket
        |> put_flash(:info, "Welcome!")
        |> redirect()
        ...
      }
  end
end

The :attested_credential_data field contains a Wax.AttestedCredentialData.t/0 struct. In this struct, the :credential_id and :credential_public_key fields must be persisted for future authentication.

WebauthnComponents defers to the host application for credential persistence and session management. Whether the application follows CRUD or Event Sourcing patterns, it is recommended to define a schema dedicated to public key credential storage:

CRUD Example

defmodule MyApp.Identity.PublicKeyCredential do
  use Ecto.Schema
  alias Ecto.Changeset
  alias MyApp.Identity.User
  alias WebauthnComponents.CoseKey
  
  @primary_key {:id, binary, autogenerate: false}
  schema "public_key_credentials" do
    field :public_key, CoseKey
    belongs_to :user, User

    # Optional: Save `:flag_*` and other fields from `t:Wax.AuthenticatorData.t/0`
    field :flags, :map, default: %{}
    field :sign_count, :integer
    field :extensions, :map, default: %{}
  end

  def changeset(struct, params) do
    fields = __MODULE__.__schema__(:fields)
  
    struct
    |> Changeset.cast(params, fields)
    |> Changeset.validate_required([:id, :public_key])
    ...
  end
end

Summary

Functions

fetch_challenge(assigns)

handle_event(binary, credential, socket)

Callback implementation for Phoenix.LiveComponent.handle_event/3.

mount(socket)

Callback implementation for Phoenix.LiveComponent.mount/1.

render(assigns)

Callback implementation for Phoenix.LiveComponent.render/1.