User registration¶
The Symfony UX WebAuthn package provides Stimulus controllers to simplify the registration of new authenticators. This page explains how to register a new user with WebAuthn or add authenticators to an existing user account.
New user registration¶
When registering a new user, you need to collect basic information (username, display name) and then register their first authenticator.
Registration form¶
Your registration form needs: 1. A username field for the user's identifier 2. A display name field (optional, can default to username) 3. A hidden field for the attestation response
<form
action="{{ path('app_register') }}"
method="post"
{{ stimulus_controller('@web-auth/webauthn-stimulus',
{
creationOptionsUrl: path('webauthn.controller.creation.request.new_user'),
creationResultField: 'input[name="attestation"]'
}
) }}
>
<label for="username">Username</label>
<input
type="text"
id="username"
name="username"
required
autocomplete="username webauthn"
>
<label for="displayName">Display Name</label>
<input
type="text"
id="displayName"
name="displayName"
placeholder="John Doe"
>
<input type="hidden" id="attestation" name="attestation">
<button
type="submit"
{{ stimulus_action('@web-auth/webauthn-stimulus', 'signup') }}
>
Register with Passkey
</button>
</form>
Bundle configuration¶
Configure the bundle to handle new user registration:
webauthn:
credential_repository: 'App\Repository\WebauthnCredentialRepository'
user_repository: 'App\Repository\UserRepository'
controllers:
enabled: true
creation:
new_user:
options_path: '/register/webauthn/options'
result_path: '/register/webauthn'
user_entity_guesser: 'App\Guesser\NewUserEntityGuesser'
User entity guesser¶
Create a guesser to handle new user registration:
<?php
declare(strict_types=1);
namespace App\Guesser;
use Symfony\Component\HttpFoundation\Request;
use Webauthn\Bundle\Security\Guesser\UserEntityGuesser;
use Webauthn\PublicKeyCredentialUserEntity;
final class NewUserEntityGuesser implements UserEntityGuesser
{
public function findUserEntity(Request $request): PublicKeyCredentialUserEntity
{
$username = $request->request->get('username');
$displayName = $request->request->get('displayName', $username);
// Generate a unique user ID (64 bytes recommended)
$userHandle = random_bytes(64);
return PublicKeyCredentialUserEntity::create(
$username,
$userHandle,
$displayName
);
}
}
Info
After successful registration, save both the user entity and the credential source to your database. The controller automatically validates the attestation response.
Adding authenticators to existing users¶
Existing users can register additional authenticators (backup keys, different devices).
Add authenticator form¶
<form
action="{{ path('app_add_authenticator') }}"
method="post"
{{ stimulus_controller('@web-auth/webauthn-stimulus',
{
creationOptionsUrl: path('webauthn.controller.creation.request.add_device'),
creationResultField: 'input[name="attestation"]'
}
) }}
>
<input type="hidden" id="attestation" name="attestation">
<button
type="submit"
{{ stimulus_action('@web-auth/webauthn-stimulus', 'signup') }}
>
Add New Authenticator
</button>
</form>
Configuration for existing users¶
webauthn:
controllers:
enabled: true
creation:
add_device:
options_path: '/devices/add/options'
result_path: '/devices/add'
user_entity_guesser: 'Webauthn\Bundle\Security\Guesser\CurrentUserEntityGuesser'
Success
The CurrentUserEntityGuesser automatically retrieves the currently authenticated user from the Symfony security context. No custom guesser needed!
Stimulus controller options¶
The registration controller accepts the following options:
| Option | Type | Required | Description |
|---|---|---|---|
creationOptionsUrl |
string | Yes | URL to fetch credential creation options |
creationResultField |
string | Yes | CSS selector for the hidden attestation field |
autoRegister |
boolean | No | Automatically trigger registration on page load (default: false) |
Auto-register example¶
Automatically start the registration process when the page loads:
{{ stimulus_controller('@web-auth/webauthn-stimulus',
{
autoRegister: true,
creationOptionsUrl: path('webauthn.controller.creation.request.new_user'),
creationResultField: 'input[name="attestation"]'
}
) }}
Warning
Use autoRegister carefully as it immediately prompts the user for biometric authentication or security key interaction.
Dedicated registration controller¶
Info
New in v5.3.0: A dedicated registration controller is available alongside the combined controller.
The dedicated registration-controller provides a focused controller for credential registration with enhanced features like conditional create support.
Basic usage¶
<form
action="{{ path('app_register') }}"
method="post"
{{ stimulus_controller('@web-auth/webauthn-stimulus/registration', {
optionsUrl: path('webauthn.controller.creation.request.new_user'),
resultUrl: path('app_register'),
submitViaForm: true
}) }}
>
<input
type="text"
name="username"
required
{{ stimulus_target('@web-auth/webauthn-stimulus/registration', 'username') }}
>
<input
type="hidden"
name="attestation"
{{ stimulus_target('@web-auth/webauthn-stimulus/registration', 'result') }}
>
<button
type="button"
{{ stimulus_action('@web-auth/webauthn-stimulus/registration', 'register') }}
>
Register with Passkey
</button>
</form>
Registration controller options¶
| Option | Type | Default | Description |
|---|---|---|---|
optionsUrl |
string | /registration/options |
URL to fetch creation options |
resultUrl |
string | /registration/verify |
URL to submit the attestation response |
submitViaForm |
boolean | false |
Submit via form instead of fetch |
successRedirectUri |
string | - | URL to redirect after successful registration |
autoRegister |
boolean | false |
Auto-start registration on page load |
Registration controller targets¶
| Target | Description |
|---|---|
username |
Input field for the username |
attestation |
Select field for attestation preference |
residentKey |
Select field for resident key preference |
userVerification |
Select field for user verification preference |
authenticatorAttachment |
Select field for authenticator attachment preference |
result |
Hidden input for the attestation response |
Error handling¶
Handle registration errors in your custom event listeners:
document.addEventListener('webauthn:registration:error', (event) => {
console.error('Registration failed:', event.detail);
alert('Could not register authenticator: ' + event.detail.message);
});
document.addEventListener('webauthn:registration:success', (event) => {
console.log('Registration successful!');
});
See also¶
- User Authentication - Authenticate users with registered authenticators
- Additional Authenticators - Manage multiple authenticators
- Bundle Configuration - Complete configuration reference