diff --git a/docs/overrides/partials/logo.html b/docs/overrides/partials/logo.html
new file mode 100644
index 0000000..e261fcf
--- /dev/null
+++ b/docs/overrides/partials/logo.html
@@ -0,0 +1,8 @@
+{#-
+ The project mark of WebAuthn Framework: the Slabs monogram, the name of the project and "by Slabs". The
+ colour version on a light ground, the reversed one on a dark ground, from the web set of the design kit
+ without their metadata (tools/web-svg.py of Spomky-Labs/docs). The link around them carries the
+ accessible name, so the images say nothing.
+-#}
+
+
diff --git a/docs/overrides/partials/source.html b/docs/overrides/partials/source.html
new file mode 100644
index 0000000..3d8f7f0
--- /dev/null
+++ b/docs/overrides/partials/source.html
@@ -0,0 +1,13 @@
+{#-
+ The link to the repository, without the stars and the forks: the theme would ask the API of GitHub for
+ them from the browser of the reader, and this site sends nothing to a third party.
+-#}
+
+
+
diff --git a/prerequisites/credential-source-repository.md b/docs/prerequisites/credential-source-repository.md
similarity index 82%
rename from prerequisites/credential-source-repository.md
rename to docs/prerequisites/credential-source-repository.md
index 18fb409..387dc2e 100644
--- a/prerequisites/credential-source-repository.md
+++ b/docs/prerequisites/credential-source-repository.md
@@ -2,9 +2,9 @@
description: Authenticator details and how to manage them
---
-# Credential Source
+# Credential source
-## Credential Source Class
+## Credential source class
After the registration of an authenticator, you will get a `Webauthn\PublicKeyCredentialSource` object. This object contains all the credential data needed to perform user authentication:
@@ -22,8 +22,7 @@ After the registration of an authenticator, you will get a `Webauthn\PublicKeyCr
* **uvInitialized**: Whether user verification was initialized (since 5.1)
* **otherUI**: Optional additional UI hints (array)
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
transports; // ['usb', 'nfc']
// Get the descriptor for authentication
$descriptor = $credentialSource->getPublicKeyCredentialDescriptor();
```
-{% endcode %}
-## Credential Source Repository
+## Credential source repository
Since 4.6.0 and except if you use the Symfony bundle, there is no interface to implement or abstract class to extend, making it easy to integrate into your application.
@@ -57,16 +55,15 @@ Your repository needs to provide two main operations:
1. **Save a credential** after registration or counter update
2. **Find credentials** by credential ID or user handle
-{% hint style="success" %}
-Whatever database you use (MySQL, PostgreSQL, MongoDB…), it is not necessary to create foreign key relationships between your users and the Credential Sources. The `userHandle` property is sufficient to link credentials to users.
-{% endhint %}
+!!! success
-### Repository Example
+ Whatever database you use (MySQL, PostgreSQL, MongoDB…), it is not necessary to create foreign key relationships between your users and the Credential Sources. The `userHandle` property is sufficient to link credentials to users.
+
+### Repository example
Here's a simple example using an array storage (for demonstration purposes):
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
add(RSA\RS256::create());
$attestationStatementSupportManager->add(PackedAttestationStatementSupport::create($coseAlgorithmManager));
```
-{% endcode %}
-{% hint style="warning" %}
-The Android SafetyNet Attestation API is deprecated. Full turndown is planned in June 2024. More information at [https://developer.android.com/training/safetynet/deprecation-timeline](https://developer.android.com/training/safetynet/deprecation-timeline)
+!!! warning
-It is not described on this page, but available in the previous versions of the documentation.
-{% endhint %}
+ The Android SafetyNet Attestation API is deprecated. Full turndown is planned in June 2024. More information at [https://developer.android.com/training/safetynet/deprecation-timeline](https://developer.android.com/training/safetynet/deprecation-timeline)
-## Metadata Statement Repository
+ It is not described on this page, but available in the previous versions of the documentation.
+
+## Metadata statement repository
Then, you must prepare an Metadata Statement Repository. This service will manage all Metadata Statements depending on their sources (local storage or distant service).
@@ -71,11 +69,11 @@ Your Metadata Statement Repository must implement the interface `Webauthn\Metada
* `findOneByAAGUID(string $aaguid)`: this method retrieves the `MetadataStatement` object with AAGUID. It shall return `null` in case of the absence of the MDS.
-{% hint style="warning" %}
-The library does not provide any Metadata Statement Repository. It is up to you to select the MDS suitable for your application and store them in your database.
-{% endhint %}
+!!! warning
+
+ The library does not provide any Metadata Statement Repository. It is up to you to select the MDS suitable for your application and store them in your database.
-## Status Report Repository
+## Status report repository
To prevent the use of rogue MDS or deprecated by the manufacturers, Status Reports may be used. The Status Report Repository is a simple service that implements the interface `Webauthn\MetadataService\StatusReportRepository` with a unique method:
@@ -83,14 +81,13 @@ To prevent the use of rogue MDS or deprecated by the manufacturers, Status Repor
The verification's success or failure depends on the state reported in the most recent Status Report.
-## Certificate Chain Validator
+## Certificate chain validator
When an attestation statement is received, a certificate chain is constructed. This chain combines certificates from the Metadata Service (MDS), which are trusted, with those provided by the authenticator, which are untrusted.
The Certificate Chain Validator is responsible for this task. The library provides the class `Webauthn\MetadataService\CertificateChain\PhpCertificateChainValidator` that requires a Symfony Http Client ([for CRL verification](https://en.wikipedia.org/wiki/Certificate_revocation_list)) and a PSR-20 Clock.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
enableMetadataStatementSupport(
$certificateChainValidator,
);
```
-{% endcode %}
-## Requesting Attestation Statement
+## Requesting attestation statement
By default, no Attestation Statement is asked to the Authenticators (type = `none`). To change this behavior, you just have to set the corresponding parameter in the `Webauthn\PublicKeyCredentialCreationOptions` object.
@@ -134,8 +128,7 @@ There are 3 conveyance modes available using PHP constants provided by the class
* `ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT`: the Relying Party prefers an attestation conveyance yielding verifiable attestation statements, but allows the client to decide how to obtain such attestation statements.
* `ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT`: the Relying Party wants to receive the attestation statement as generated by the authenticator.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setAlgorithmManager($algorithmManager);
```
-{% endcode %}
diff --git a/pure-php/advanced-behaviours/authenticator-counter.md b/docs/pure-php/advanced-behaviours/authenticator-counter.md
similarity index 92%
rename from pure-php/advanced-behaviours/authenticator-counter.md
rename to docs/pure-php/advanced-behaviours/authenticator-counter.md
index ce3c255..22fb159 100644
--- a/pure-php/advanced-behaviours/authenticator-counter.md
+++ b/docs/pure-php/advanced-behaviours/authenticator-counter.md
@@ -1,4 +1,4 @@
-# Authenticator Counter
+# Authenticator counter
The authenticators may have an internal counter. This feature is very helpful to detect cloned devices.
@@ -8,13 +8,11 @@ It is therefore required to go deeper in the protection of your application by l
To do so , you have to create a custom Counter Checker and inject it to your Authenticator Assertion Response Validator. The checker must implement the interface `Webauthn\Counter\CounterChecker`.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setCounterChecker($customCounterChecker);
```
-{% endcode %}
diff --git a/pure-php/advanced-behaviours/authenticator-selection-criteria.md b/docs/pure-php/advanced-behaviours/authenticator-selection-criteria.md
similarity index 88%
rename from pure-php/advanced-behaviours/authenticator-selection-criteria.md
rename to docs/pure-php/advanced-behaviours/authenticator-selection-criteria.md
index 2a06ee7..9d36749 100644
--- a/pure-php/advanced-behaviours/authenticator-selection-criteria.md
+++ b/docs/pure-php/advanced-behaviours/authenticator-selection-criteria.md
@@ -1,4 +1,4 @@
-# Authenticator Selection Criteria
+# Authenticator selection criteria
By default, any type of authenticator can be used by your users and interact with you application. In certain circumstances, you may need to select specific authenticators e.g. when user verification is required.
@@ -6,9 +6,9 @@ The Webauthn API and this library allow you to define a set of options to disall
The class `Webauthn\AuthenticatorSelectionCriteria` is designed for this purpose. It is used when generating the `Webauthn\PublicKeyCredentialCreationOptions` object.
-## Available Criteria
+## Available criteria
-### Authenticator Attachment Modality
+### Authenticator attachment modality
You can indicate if the authenticator must be attached to the client (platform authenticator i.e. it is usually not removable from the client device) or must be detached (roaming authenticator).
@@ -20,15 +20,15 @@ Possible values are:
A primary use case for platform authenticators is to register a particular client device as a "trusted device" for future authentication. This gives the user the convenience benefit of not needing a roaming authenticator, e.g., the user will not have to dig around in their pocket for their key fob or phone.
-### Resident Key
+### Resident key
With this criterion, a Public Key Credential Source will be stored in the authenticator, client or client device. Such storage requires an authenticator capable to store such a resident credential.
-{% hint style="info" %}
-A resident key shall be created if you want to [authenticate users without username](authentication-without-username.md).
-{% endhint %}
+!!! info
-### User Verification
+ A resident key shall be created if you want to [authenticate users without username](authentication-without-username.md).
+
+### User verification
[Please refer to this page](user-verification.md).
@@ -36,8 +36,7 @@ A resident key shall be created if you want to [authenticate users without usern
With this example, with require the user verification (PIN, fingerprint...), a resident key and an authenticator embedded onto a device. This is typacally what you will require for Windows Hello or Face ID authentication.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
@@ -55,4 +54,3 @@ $publicKeyCredentialCreationOptions =
authenticatorSelection: $authenticatorSelectionCriteria
);
```
-{% endcode %}
diff --git a/pure-php/advanced-behaviours/dealing-with-localhost.md b/docs/pure-php/advanced-behaviours/dealing-with-localhost.md
similarity index 81%
rename from pure-php/advanced-behaviours/dealing-with-localhost.md
rename to docs/pure-php/advanced-behaviours/dealing-with-localhost.md
index 7e9bf6f..eb66a09 100644
--- a/pure-php/advanced-behaviours/dealing-with-localhost.md
+++ b/docs/pure-php/advanced-behaviours/dealing-with-localhost.md
@@ -1,4 +1,4 @@
-# Cross Origin Authentication
+# Cross origin authentication
## Default behavior
@@ -9,22 +9,21 @@ By default, the current host is used, and the origin parameter returned in the W
* **Subdomain authentication**: Some deployments use a wildcard subdomain approach (e.g., `tenant1.example.com`, `tenant2.example.com`), but strict origin checking will reject authentication if the relying party ID does not match exactly.
* **Development and testing environments**: Local development often uses `http://localhost`, which is not allowed by default due to the HTTPS requirement.
-## Customizing Allowed Origins
+## Customizing allowed origins
To handle these cases, you can explicitly define a list of allowed origins when configuring the WebAuthn authentication process using the method `setAllowedOrigins`.
-{% hint style="info" %}
-The method `setSecuredRelyingPartyId` is deprecated since 5.2.0
-{% endhint %}
+!!! info
-### Allowing Multiple Origins
+ The method `setSecuredRelyingPartyId` is deprecated since 5.2.0
+
+### Allowing multiple origins
If your application supports multiple domains, specify them explicitly:
This ensures that authentication requests coming from any of these origins are accepted.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setAllowedOrigins([
'https://old-acme.com'
]);
```
-{% endcode %}
-### Allowing Subdomains
+### Allowing subdomains
To allow authentication from subdomains dynamically, enable the `allowSubdomains` flag:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setAllowedOrigins(['https://acme.com'], true);
```
-{% endcode %}
With this setting, authentication requests from `https://sub.acme.com` will be considered valid.
-{% hint style="danger" %}
-Do not use TLD and the sub domain flag together! `$csmFactory->setSecuredRelyingPartyId(['com'], true);`
-{% endhint %}
+!!! danger
+
+ Do not use TLD and the sub domain flag together! `$csmFactory->setSecuredRelyingPartyId(['com'], true);`
-### Supporting Native Applications
+### Supporting native applications
For native applications, origins are different from traditional web URLs. If your application integrates with mobile apps, ensure that relevant origins are included:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setAllowedOrigins([
'ios:bundle-id://your.bundle.id',
]);
```
-{% endcode %}
This configuration allows authentication responses from web browsers and native applications.
-### Enabling `http://localhost` for Development
+### Enabling `http://localhost` for development
During local development, you may need to allow `http://localhost`. Since WebAuthn generally requires HTTPS, this is an exception for local testing. To allow it:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setAllowedOrigins([
'http://localhost.com',
]);
```
-{% endcode %}
Be aware that this should only be enabled in non-production environments.
-## Top Origin Validation (Cross-Origin iframes)
+## Top origin validation (cross-origin iframes)
When your WebAuthn authentication is embedded in a cross-origin iframe (e.g., `auth.example.com` is loaded inside an iframe on `app.example.com`), the browser includes a `topOrigin` field in the client data. By default, the library **does not validate** this field.
If you need to restrict which top-level origins are allowed to embed your authentication page, you must explicitly enable top origin validation by providing a `TopOriginValidator` implementation.
-### Using the Built-in Host Validator
+### Using the built-in host validator
The `HostTopOriginValidator` performs a strict comparison between the top origin and a given host:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
enableTopOriginValidator(
new HostTopOriginValidator('app.example.com')
);
```
-{% endcode %}
-### Using a Custom Validator
+### Using a custom validator
For more advanced scenarios (e.g., allowing multiple top origins), implement the `TopOriginValidator` interface:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
enableTopOriginValidator(
new AllowedTopOriginsValidator([
'https://app.example.com',
@@ -180,13 +167,12 @@ $csmFactory->enableTopOriginValidator(
])
);
```
-{% endcode %}
-{% hint style="warning" %}
-If you do not call `enableTopOriginValidator()`, the top origin is **not validated**. Enable it if your authentication page can be embedded in cross-origin iframes and you want to control which parent origins are permitted.
-{% endhint %}
+!!! warning
+
+ If you do not call `enableTopOriginValidator()`, the top origin is **not validated**. Enable it if your authentication page can be embedded in cross-origin iframes and you want to control which parent origins are permitted.
-## Security Considerations
+## Security considerations
When modifying allowed origins, ensure that:
diff --git a/pure-php/advanced-behaviours/debugging.md b/docs/pure-php/advanced-behaviours/debugging.md
similarity index 88%
rename from pure-php/advanced-behaviours/debugging.md
rename to docs/pure-php/advanced-behaviours/debugging.md
index dfae766..377be3f 100644
--- a/pure-php/advanced-behaviours/debugging.md
+++ b/docs/pure-php/advanced-behaviours/debugging.md
@@ -2,16 +2,15 @@
WebAuthn operations can be complex to debug due to the cryptographic operations and browser interactions involved. This page explains how to enable logging to troubleshoot issues during development or monitor your application in production.
-## PSR-3 Logger Integration
+## PSR-3 logger integration
The WebAuthn library supports [PSR-3 compatible loggers](https://www.php-fig.org/psr/psr-3/) for debugging and monitoring. You can use any PSR-3 logger implementation such as Monolog, Symfony Logger, or others.
-### Setting Up a Logger
+### Setting up a logger
Several WebAuthn classes implement the `Webauthn\MetadataService\CanLogData` interface, allowing you to inject a PSR-3 logger:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
setLogger($logger);
$assertionValidator = AuthenticatorAssertionResponseValidator::create($requestCSM);
$assertionValidator->setLogger($logger);
```
-{% endcode %}
-## What Gets Logged
+## What gets logged
The WebAuthn library logs various events during authentication and registration:
-### Registration (Attestation) Events
+### Registration (attestation) events
* Challenge generation and validation
* Client data validation
@@ -49,7 +47,7 @@ The WebAuthn library logs various events during authentication and registration:
* Certificate chain validation (when using attestation)
* Errors during any step
-### Authentication (Assertion) Events
+### Authentication (assertion) events
* Challenge validation
* Credential lookup
@@ -58,7 +56,7 @@ The WebAuthn library logs various events during authentication and registration:
* User presence and verification checks
* Errors during any step
-## Log Levels
+## Log levels
The library uses standard PSR-3 log levels:
@@ -68,7 +66,7 @@ The library uses standard PSR-3 log levels:
* **ERROR**: Error messages for failures
* **CRITICAL**: Critical errors requiring immediate attention
-## Example Log Output
+## Example log output
Here's what typical log messages look like:
@@ -86,14 +84,13 @@ In case of errors:
[2025-01-15 10:31:12] webauthn.CRITICAL: Signature verification failed
```
-## Development vs Production
+## Development vs production
-### Development Environment
+### Development environment
Enable verbose DEBUG logging to see all operations:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
pushHandler(
new StreamHandler('php://stdout', LogLevel::DEBUG)
);
```
-{% endcode %}
-### Production Environment
+### Production environment
In production, log only warnings and errors to avoid performance impact:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
pushHandler(
)
);
```
-{% endcode %}
-## Common Issues and Log Messages
+## Common issues and log messages
### "Challenge mismatch"
@@ -154,41 +148,39 @@ $logger->pushHandler(
**Solution**: Check your Relying Party ID configuration matches your domain.
-### "User not present" or "User not verified"
+### "User not present" or "user not verified"
**Cause**: User verification requirements not met.
**Solution**: Check your authenticator selection criteria configuration.
-## Additional Debugging Tools
+## Additional debugging tools
-### Browser Developer Tools
+### Browser developer tools
Modern browsers provide WebAuthn debugging in developer tools:
* **Chrome/Edge**: DevTools → Application → WebAuthn
* **Firefox**: about:config → search for "webauthn"
-### Network Inspector
+### Network inspector
Monitor the network requests to see:
* Options requests (registration/authentication)
* Response data being sent back
* HTTP errors or timeouts
-### Test Authenticators
+### Test authenticators
Use virtual authenticators for testing:
-{% code lineNumbers="true" %}
-```javascript
+```javascript linenums="1"
// Chrome DevTools Protocol
// Enable virtual authenticator in Chrome DevTools → Application → WebAuthn
// Add Virtual Authenticator → Configure options
```
-{% endcode %}
-## See Also
+## See also
* [Symfony Bundle Debugging](../../symfony-bundle/advanced-behaviors/debugging.md) - Framework-specific logging
* [Authenticator Counter](authenticator-counter.md) - Detect cloned authenticators
diff --git a/pure-php/advanced-behaviours/extensions.md b/docs/pure-php/advanced-behaviours/extensions.md
similarity index 88%
rename from pure-php/advanced-behaviours/extensions.md
rename to docs/pure-php/advanced-behaviours/extensions.md
index 89b3e65..73a469d 100644
--- a/pure-php/advanced-behaviours/extensions.md
+++ b/docs/pure-php/advanced-behaviours/extensions.md
@@ -2,8 +2,7 @@
The following example is totally fictive. We will add an extension input `loc=true` to the request option object.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
add(new LocationExtensionOutputChecker());
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setExtensionOutputCheckerHandler($eocHandler);
```
-{% endcode %}
diff --git a/pure-php/advanced-behaviours/user-verification.md b/docs/pure-php/advanced-behaviours/user-verification.md
similarity index 85%
rename from pure-php/advanced-behaviours/user-verification.md
rename to docs/pure-php/advanced-behaviours/user-verification.md
index d6a4088..6c91db1 100644
--- a/pure-php/advanced-behaviours/user-verification.md
+++ b/docs/pure-php/advanced-behaviours/user-verification.md
@@ -1,11 +1,10 @@
-# User Verification
+# User verification
You can indicate the user verification requirements during the ceremonies by setting the value in your options.
### Authenticator registration
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
@@ -18,12 +17,10 @@ $publicKeyCredentialCreationOptions =
)
;
```
-{% endcode %}
-### User Authentication
+### User authentication
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Public Key Credential Request Options
use Webauthn\PublicKeyCredentialRequestOptions;
@@ -32,4 +29,3 @@ $publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DISCOURAGED
);
```
-{% endcode %}
diff --git a/pure-php/authenticate-your-users.md b/docs/pure-php/authenticate-your-users.md
similarity index 83%
rename from pure-php/authenticate-your-users.md
rename to docs/pure-php/authenticate-your-users.md
index 92859a4..4adfd67 100644
--- a/pure-php/authenticate-your-users.md
+++ b/docs/pure-php/authenticate-your-users.md
@@ -1,8 +1,8 @@
-# Authenticate Your Users
+# Authenticate your users
During this step, your application will send a challenge to the list of registered devices of the user. The security token will resolve this challenge by adding information and digitally signing the data.
-## Assertion Request
+## Assertion request
To perform a user authentication using a security device, you need to instantiate a `Webauthn\PublicKeyCredentialRequestOptions` object.
@@ -20,19 +20,18 @@ Optionally, you can customize the following parameters:
The `PublicKeyCredentialRequestOptions` object is designed to be easily serialized into a JSON object. This will ease the integration into an HTML page or through an API endpoint.
-{% hint style="info" %}
-The timeout default value is set to `null`. If you want to set a value, please read the following recommended behavior showed in the specification:
+!!! info
-* If the user verification is `discouraged`, timeout should be between 30 and 180 seconds
-* If the user verification is `preferred` or `required`, the range is 300 to 600 seconds (5 to 10 minutes)
-{% endhint %}
+ The timeout default value is set to `null`. If you want to set a value, please read the following recommended behavior showed in the specification:
-### Allowed Credentials
+ * If the user verification is `discouraged`, timeout should be between 30 and 180 seconds
+ * If the user verification is `preferred` or `required`, the range is 300 to 600 seconds (5 to 10 minutes)
+
+### Allowed credentials
The user trying to authenticate must have registered at least one device. For this user, you have to get all `Webauthn\PublicKeyCredentialDescriptor` associated to his account.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialDescriptor;
@@ -50,20 +49,18 @@ $allowedCredentials = array_map(
$registeredAuthenticators
);
```
-{% endcode %}
-{% hint style="info" %}
-For usernameless authentication, please read the [dedicated page](advanced-behaviours/authentication-without-username.md). In this case no Public Key Credential Descriptors should be passed to the options.
-{% endhint %}
+!!! info
+
+ For usernameless authentication, please read the [dedicated page](advanced-behaviours/authentication-without-username.md). In this case no Public Key Credential Descriptors should be passed to the options.
+
+!!! danger
-{% hint style="danger" %}
-To prevent username enumeration, when the authentication process is performed using the username, it is highly recommended to continue the ceremony even if the user entity does not exist. The allowed credential list should be set with random data.
-{% endhint %}
+ To prevent username enumeration, when the authentication process is performed using the username, it is highly recommended to continue the ceremony even if the user entity does not exist. The allowed credential list should be set with random data.
### Example
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
deserialize($data, PublicKeyCredential::class, 'json');
```
-{% endcode %}
-### Response Verification
+### Response verification
Now we have a fully loaded Public Key Credential object, but we need now to make sure that:
@@ -201,8 +189,7 @@ Now we have a fully loaded Public Key Credential object, but we need now to make
The first is easy to perform:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
response instanceof AuthenticatorAssertionResponse) {
//e.g. process here with a redirection to the public key login/MFA page.
}
```
-{% endcode %}
The second step is the verification against the Public Key Assertion Options we created earlier.
The Authenticator Assertion Response Validator service (variable `$authenticatorAssertionResponseValidator`) will check everything for you.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
check(
$publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource);
```
-{% endcode %}
If no exception is thrown, the response is valid and you can continue the authentication of the user.
diff --git a/pure-php/authenticator-registration.md b/docs/pure-php/authenticator-registration.md
similarity index 81%
rename from pure-php/authenticator-registration.md
rename to docs/pure-php/authenticator-registration.md
index 0527451..ca3a8f2 100644
--- a/pure-php/authenticator-registration.md
+++ b/docs/pure-php/authenticator-registration.md
@@ -1,10 +1,10 @@
-# Register Authenticators
+# Register authenticators
During this step, your application will send a challenge to the device. The device will resolve this challenge by adding information and digitally signing the data.
The application will check the response from the device and get its credential ID. This ID will be used for further authentication requests.
-## Creation Request
+## Creation request
To associate a device to a user, you need to instantiate a `Webauthn\PublicKeyCredentialCreationOptions` object.
@@ -25,8 +25,7 @@ Optionally, you can customize the following parameters:
Let’s see an example of the `PublicKeyCredentialCreationOptions` object. The following example is a possible Public Key Creation page for a dummy user "@cypher-Angel-3000".
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
serialize(
);
```
-{% hint style="warning" %}
-It is important to store the user entity and the options object (e.g. in the session) for the next step. The data will be needed to check the response from the device.
-{% endhint %}
+!!! warning
+
+ It is important to store the user entity and the options object (e.g. in the session) for the next step. The data will be needed to check the response from the device.
You can change the default values for each and all options
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\AuthenticatorSelectionCriteria;
$publicKeyCredentialCreationOptions =
@@ -98,16 +95,14 @@ $publicKeyCredentialCreationOptions =
)
;
```
-{% endcode %}
-### Public Key Credential Parameters
+### Public key credential parameters
The argument `pubKeyCredParams` contains a list of `Webauthn\PublicKeyCredentialParameters` objects that refer to COSE algorithms. The authenticators must use one of the algorithms in this list, respecting the order of preference on this list.
An empty list corresponds to the default algorithms that are `ES256` and `RS256` (in this order). Those two algorithms are required by the specification.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Cose\Algorithms;
use Webauthn\PublicKeyCredentialParameters;
@@ -119,13 +114,12 @@ $publicKeyCredentialParametersList = [
PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ED256), // Less interesting algorithm
];
```
-{% endcode %}
-{% hint style="warning" %}
-Customizing this list may lead to unexpected behavior. Please use with caution.
-{% endhint %}
+!!! warning
-### Authenticator Selection
+ Customizing this list may lead to unexpected behavior. Please use with caution.
+
+### Authenticator selection
Please read detail [on this page](advanced-behaviours/authenticator-selection-criteria.md).
@@ -133,12 +127,11 @@ Please read detail [on this page](advanced-behaviours/authenticator-selection-cr
Please read detail [on this page](advanced-behaviours/attestation-and-metadata-statement.md).
-### Exclude Credentials
+### Exclude credentials
When the user already registered authenticators, you can pass a list of `Webauthn\PublicKeyCredentialDescriptor` objects as argument to avoid registering multiple times the same authenticator.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialDescriptor;
@@ -157,20 +150,18 @@ $publicKeyCredentialCreationOptions =
)
;
```
-{% endcode %}
-{% hint style="danger" %}
-To avoid username enumeration, you should not set any excluded credential when the authenticator registration is performed for anonymous users. If this value is present, it indicates that the username exists and has registered credentials.
+!!! danger
+
+ To avoid username enumeration, you should not set any excluded credential when the authenticator registration is performed for anonymous users. If this value is present, it indicates that the username exists and has registered credentials.
-On the contrary when adding new authenticators to already authenticated users, this value should be set.
-{% endhint %}
+ On the contrary when adding new authenticators to already authenticated users, this value should be set.
-## Creation Response
+## Creation response
What you receive must be a JSON object that looks like as follow:
-{% code lineNumbers="true" %}
-```javascript
+```javascript linenums="1"
{
"id":"KVb8CnwDjpgAo[…]op61BTLaa0tczXvz4JrQ23usxVHA8QJZi3L9GZLsAtkcVvWObA",
"type":"public-key",
@@ -181,19 +172,19 @@ What you receive must be a JSON object that looks like as follow:
}
}
```
-{% endcode %}
There are two steps to perform with this object:
* [Load the data](input-loading.md)
* [Verify it with the creation options set above](input-validation.md)
-### Data Loading
+### Data loading
-Now that all components are set, we can load the data we receive using the [_Serializer_](webauthn-server.md#the-serializer) (variable `$serializer`).
+Now that all components are set, we can load the data we receive using the [_Serializer_](input-loading.md#the-serializer) (variable `$serializer`).
+
+```php linenums="1" hl_lines="1"
+<?php
-
declare(strict_types=1);
use Webauthn\PublicKeyCredential;
@@ -214,11 +205,11 @@ $publicKeyCredential = $serializer->deserialize(
PublicKeyCredential::class,
'json'
);
-
+```
If no exception is thrown, you can go to the next step: the verification.
-### Response Verification
+### Response verification
Now we have a fully loaded Public Key Credential object, but we need now to make sure that:
@@ -227,8 +218,7 @@ Now we have a fully loaded Public Key Credential object, but we need now to make
The first step is easy to perform:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
response instanceof AuthenticatorAttestationResponse)
//e.g. process here with a redirection to the public key creation page.
}
```
-{% endcode %}
The second step is the verification against
@@ -248,8 +237,7 @@ The second step is the verification against
The Authenticator Attestation Response Validator service (variable `$authenticatorAttestationResponseValidator`) will check everything for you: challenge, origin, attestation statement and much more.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
check(
'my-application.com'
);
```
-{% endcode %}
If no exception is thrown, the response is valid. You can store the Public Key Credential Source (`$publicKeyCredentialSource`).
-{% hint style="info" %}
-The way you store and associate these objects to the user is out of scope of this library.
-{% endhint %}
+!!! info
+
+ The way you store and associate these objects to the user is out of scope of this library.
diff --git a/pure-php/input-loading.md b/docs/pure-php/input-loading.md
similarity index 79%
rename from pure-php/input-loading.md
rename to docs/pure-php/input-loading.md
index cedbaa5..72282c1 100644
--- a/pure-php/input-loading.md
+++ b/docs/pure-php/input-loading.md
@@ -1,14 +1,14 @@
-# Input Loading
+# Input loading
In general, the data you receive is an encoded JSON object. The library provides utilities to convert the string into objects.
To do so, you will need an Attestation Statement Support Manager and a Serializer.
-## Attestation Statement Support Manager
+## Attestation statement support manager
Authenticator Responses may contain an Attestation Statement. This attestation holds data regarding the authenticator depending on several factors such as its manufacturer and model, what you asked in the options, the capabilities of the browser or what the user allowed.
-### Supported Attestation Statement Types
+### Supported attestation statement types
The following attestation types are supported. Note that you should only use the `none` one unless you have specific needs described in [the dedicated page](../webauthn-in-a-nutshell/attestation-and-metadata-statement.md).
@@ -19,8 +19,7 @@ The following attestation types are supported. Note that you should only use the
* `trusted platform module`: for devices with built-in security chips.
* `apple`: for Apple devices
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
add(NoneAttestationStatementSupport::create());
```
-{% endcode %}
-## The Serializer
+## The serializer
To convert Authenticator Responses from the encoded string to an object, you will need a Serializer. It only needs the Attestation Statement Support Manager created above.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
create();
```
-{% endcode %}
-{% hint style="danger" %}
-Please do not use `json_encode` or `json_decode` to convert this data either way.
-{% endhint %}
+!!! danger
-## Loading Data
+ Please do not use `json_encode` or `json_decode` to convert this data either way.
+
+## Loading data
In general, the data you receive looks like as follows.
-{% code lineNumbers="true" %}
-```json
+```json linenums="1"
{
"id":"KVb8CnwDjpgAo[…]op61BTLaa0tczXvz4JrQ23usxVHA8QJZi3L9GZLsAtkcVvWObA",
"type":"public-key",
@@ -71,14 +66,14 @@ In general, the data you receive looks like as follows.
}
}
```
-{% endcode %}
-{% hint style="info" %}
-Only this type of input is supported. If you receive other forms of data, please contact us.
-{% endhint %}
+!!! info
+
+ Only this type of input is supported. If you receive other forms of data, please contact us.
+
+```php linenums="1" hl_lines="1"
+<?php
-
declare(strict_types=1);
use Webauthn\PublicKeyCredential;
@@ -89,10 +84,10 @@ $publicKeyCredential = $serializer->deserialize(
PublicKeyCredential::class,
'json'
);
-
+```
If the data is correctly loaded, the variable `$publicKeyCredential` will be an instance of `Webauthn\PublicKeyCredential`. An exception is thrown in case of an error.
-{% hint style="danger" %}
-At this stage, the data is not verified.
-{% endhint %}
+!!! danger
+
+ At this stage, the data is not verified.
diff --git a/pure-php/input-validation.md b/docs/pure-php/input-validation.md
similarity index 57%
rename from pure-php/input-validation.md
rename to docs/pure-php/input-validation.md
index 050bb8f..b824c9b 100644
--- a/pure-php/input-validation.md
+++ b/docs/pure-php/input-validation.md
@@ -1,13 +1,12 @@
-# Input Validation
+# Input validation
The loaded data needs to be verified. The library will perform several actions to make sure the input you received is valid. This verification process is performed by a Ceremony Step Manager (CSM). The Webauthn Specification distinguish two types of ceremonies [described in this page](../webauthn-in-a-nutshell/ceremonies.md).
-## Ceremony Step Manager Factory
+## Ceremony step manager factory
To facilitate the creation of the CSM, a default factory is included. This factory requires no external services to function.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
creationCeremony();
$requestCSM = $csmFactory->requestCeremony();
```
-{% endcode %}
-{% hint style="info" %}
-You can customize its behavior to fit the specific needs of your application by modifying the provided factory. Please refer to the dedicated pages for more information.
+!!! info
-* [Counter Checker](advanced-behaviours/authenticator-counter.md)
-* [Attestation Statement Support Manager](advanced-behaviours/attestation-and-metadata-statement.md#attestation-statement-support-manager)
-* [Extension Output Checker Handler](advanced-behaviours/extensions.md)
-* [Algorithm Manager](advanced-behaviours/authenticator-algorithms.md)
-* [Metadata Statement Repository](advanced-behaviours/attestation-and-metadata-statement.md#metadata-statement-repository)
-* [Status Report Repository](advanced-behaviours/attestation-and-metadata-statement.md#status-report-repository)
-* [Certification Chain Validator](advanced-behaviours/attestation-and-metadata-statement.md#certificate-chain-validator)
-{% endhint %}
+ You can customize its behavior to fit the specific needs of your application by modifying the provided factory. Please refer to the dedicated pages for more information.
+
+ * [Counter Checker](advanced-behaviours/authenticator-counter.md)
+ * [Attestation Statement Support Manager](advanced-behaviours/attestation-and-metadata-statement.md#attestation-statement-support-manager)
+ * [Extension Output Checker Handler](advanced-behaviours/extensions.md)
+ * [Algorithm Manager](advanced-behaviours/authenticator-algorithms.md)
+ * [Metadata Statement Repository](advanced-behaviours/attestation-and-metadata-statement.md#metadata-statement-repository)
+ * [Status Report Repository](advanced-behaviours/attestation-and-metadata-statement.md#status-report-repository)
+ * [Certification Chain Validator](advanced-behaviours/attestation-and-metadata-statement.md#certificate-chain-validator)
These CSM services are meant to be used by Response Validators. On a similar way, there are two types of validators:
* **Authenticator Attestation Response Validator**: used during the creation ceremony
* **Authenticator Assertion Response Validator**: used during the request ceremony
-## Response Validators
+## Response validators
The Authenticator Attestation Response Validator and Authenticator Assertion Response Validator services are directly used when receiving Authenticator Responses in order to [register authenticators](authenticator-registration.md) or [authenticate users](authenticate-your-users.md).
-{% hint style="info" %}
-All null values below correspond to deprecated parameters. They will be removed in 5.0.0
-{% endhint %}
+!!! info
+
+ All null values below correspond to deprecated parameters. They will be removed in 5.0.0
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
check(
// 5. Store the credential
$credentialRepository->saveCredentialSource($credentialSource);
```
-{% endcode %}
-### Authentication Flow
+### Authentication flow
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
check(
// 5. Update credential (counter may have changed)
$credentialRepository->saveCredentialSource($updatedCredential);
```
-{% endcode %}
-## Minimal Setup Example
+## Minimal setup example
Here's a minimal working example with in-memory storage:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
console.log('Registration failure'))
;
```
-{% endcode %}
-### Creation Profile
+### Creation profile
The `default` [creation profile](../configuration-references.md#creation-profiles) is used. You can change it using the dedicated option.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -137,9 +127,8 @@ webauthn:
…
profile: custom_profile
```
-{% endcode %}
-### Response Handlers
+### Response handlers
You can customize the responses returned by the controllers by using custom handlers. This could be useful when you want to return additional information to your application.
@@ -149,12 +138,11 @@ There are 3 types of responses and handlers:
* Success,
* Failure.
-#### Creation Options Handler
+#### Creation options handler
This handler is called during the registration of a authenticator and has to implement the interface `Webauthn\Bundle\Security\Handler\CreationOptionsHandler`.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -163,14 +151,12 @@ webauthn:
…
options_handler: … # Your handler here
```
-{% endcode %}
-#### Success Handler
+#### Success handler
This handler is called when a client sends a valid assertion from the authenticator. This handler shall implement the interface `Webauthn\Bundle\Security\Handler\SuccessHandler`. The default handler is `Webauthn\Bundle\Service\DefaultSuccessHandler`.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -179,14 +165,12 @@ webauthn:
…
success_handler: … # Your handler here
```
-{% endcode %}
-#### Failure Handler
+#### Failure handler
This handler is called when an error occurred during the process. This handler shall implement the interface `Webauthn\Bundle\Security\Handler\SuccessHandler`. The default handler is `Webauthn\Bundle\Service\DefaultFailureHandler`.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -195,4 +179,3 @@ webauthn:
…
failure_handler: … # Your handler here
```
-{% endcode %}
diff --git a/symfony-bundle/advanced-behaviors/user-verification.md b/docs/symfony-bundle/advanced-behaviors/user-verification.md
similarity index 85%
rename from symfony-bundle/advanced-behaviors/user-verification.md
rename to docs/symfony-bundle/advanced-behaviors/user-verification.md
index a6ae284..00bae3f 100644
--- a/symfony-bundle/advanced-behaviors/user-verification.md
+++ b/docs/symfony-bundle/advanced-behaviors/user-verification.md
@@ -1,9 +1,8 @@
-# User Verification
+# User verification
The easiest way to manage the user verification requirements in your Symfony application is by using the creation and request profiles.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
…
creation_profiles:
@@ -18,4 +17,3 @@ webauthn:
rp_id: 'example.com'
user_verification: !php/const Webauthn\AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED
```
-{% endcode %}
diff --git a/symfony-bundle/configuration-references.md b/docs/symfony-bundle/configuration-references.md
similarity index 74%
rename from symfony-bundle/configuration-references.md
rename to docs/symfony-bundle/configuration-references.md
index 31d674b..b2c8051 100644
--- a/symfony-bundle/configuration-references.md
+++ b/docs/symfony-bundle/configuration-references.md
@@ -1,4 +1,4 @@
-# Configuration References
+# Configuration references
## Configuration
@@ -8,8 +8,7 @@ You may also need to adjust other parameters.
If you don’t use Flex, hereafter an example of configuration file:
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
# logger: null # PSR-3 compatible logging service
credential_repository: 'Webauthn\Bundle\Repository\DummyPublicKeyCredentialSourceRepository' # CREATE YOUR REPOSITORY AND CHANGE THIS!
@@ -61,28 +60,26 @@ webauthn:
# status_report_repository: 'App\Repository\StatusReportRepository'
# certificate_chain_checker: 'App\Security\CertificateChainChecker'
```
-{% endcode %}
-### Creation Profiles
+### Creation profiles
-{% hint style="success" %}
-If you don't create the `creation_profiles` section, a `default` profile is set.
-{% endhint %}
+!!! success
-#### Relying Party (rp)
+ If you don't create the `creation_profiles` section, a `default` profile is set.
+
+#### Relying party (rp)
The relying Party corresponds to your application. Please refer [to this page](../prerequisites/the-relying-party.md) for more information.
-{% hint style="warning" %}
-The parameter `id` is optional but highly recommended.
-{% endhint %}
+!!! warning
+
+ The parameter `id` is optional but highly recommended.
-#### Challenge Length
+#### Challenge length
By default, the length of the challenge is 32 bytes. You may need to select a smaller or higher length. This length can be configured for each profile:
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -90,14 +87,12 @@ webauthn:
name: 'ACME Webauthn Server'
challenge_length: 16
```
-{% endcode %}
#### Timeout
The default timeout is set to 60 seconds (60 000 milliseconds). You can change this value as follows:
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -105,23 +100,21 @@ webauthn:
name: 'ACME Webauthn Server'
timeout: 30000
```
-{% endcode %}
-{% hint style="info" %}
-For v4.0+, the timeout is set to `null`. The values recommended by the specification are as follow:
+!!! info
-* If the user verification is `discouraged`, timeout should be between 30 and 180 seconds
-* If the user verification is `preferred` or `required`, the range is 300 to 600 seconds (5 to 10 minutes)
+ For v4.0+, the timeout is set to `null`. The values recommended by the specification are as follow:
-These behaviors are not necessarily followed by the web browsers.
-{% endhint %}
+ * If the user verification is `discouraged`, timeout should be between 30 and 180 seconds
+ * If the user verification is `preferred` or `required`, the range is 300 to 600 seconds (5 to 10 minutes)
-#### Authenticator Selection Criteria
+ These behaviors are not necessarily followed by the web browsers.
+
+#### Authenticator selection criteria
This set of options allows you to select authenticators depending on their capabilities. The values are described in [the advanced concepts](../pure-php/advanced-behaviours/authenticator-selection-criteria.md) of the protocol.
-{% code title="app/config/webauthn.yaml" lineNumbers="true" fullWidth="false" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -132,22 +125,20 @@ webauthn:
require_resident_key: true
user_verification: !php/const Webauthn\AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED
```
-{% endcode %}
-#### Public Key Credential Parameters
+#### Public key credential parameters
This option indicates the algorithms allowed for your application. By default, a large list of algorithms is defined, but you can add custom algorithms or reduce the list.
-{% hint style="info" %}
-The order is important. Preferred algorithms go first.
-{% endhint %}
+!!! info
+
+ The order is important. Preferred algorithms go first.
-{% hint style="warning" %}
-It is not recommended changing the default list unless you exactly know what you are doing.
-{% endhint %}
+!!! warning
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+ It is not recommended changing the default list unless you exactly know what you are doing.
+
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -157,18 +148,16 @@ webauthn:
- !php/const Cose\Algorithms::COSE_ALGORITHM_ES256
- !php/const Cose\Algorithms::COSE_ALGORITHM_RS256
```
-{% endcode %}
-#### Attestation Conveyance
+#### Attestation conveyance
If you need the [attestation of the authenticator](../webauthn-in-a-nutshell/attestation-and-metadata-statement.md), you can specify the preference regarding attestation conveyance during credential generation.
-{% hint style="warning" %}
-The use of Attestation Statements is generally not recommended unless you REALLY need this information.
-{% endhint %}
+!!! warning
+
+ The use of Attestation Statements is generally not recommended unless you REALLY need this information.
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -176,18 +165,16 @@ webauthn:
name: 'ACME Webauthn Server'
attestation_conveyance: !php/const Webauthn\PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT
```
-{% endcode %}
#### Extensions
You can set as many extensions as you want in the profile. Please also [refer to this page](../webauthn-in-a-nutshell/extensions.md) for more information.
-{% hint style="info" %}
-The example below is totally fictive. Some extensions are [defined in the specification](https://www.w3.org/TR/webauthn/#sctn-defined-extensions) but the support depends on the authenticators, on the browsers and on the relying parties (your applications).
-{% endhint %}
+!!! info
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+ The example below is totally fictive. Some extensions are [defined in the specification](https://www.w3.org/TR/webauthn/#sctn-defined-extensions) but the support depends on the authenticators, on the browsers and on the relying parties (your applications).
+
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
creation_profiles:
acme:
@@ -197,31 +184,26 @@ webauthn:
loc: true
txAuthSimple: 'Please add your new authenticator'
```
-{% endcode %}
-### Request Profiles
+### Request profiles
+
+!!! success
-{% hint style="success" %}
-If you don't create the `creation_profiles` section, a `default` profile is set.
-{% endhint %}
+ If you don't create the `creation_profiles` section, a `default` profile is set.
The parameters for the request profiles (i.e. the authentication) are very similar to the creation profiles. The only difference is that you don’t need all the detail of the Relying Party, but only its ID (i.e. its domain).
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
request_profiles:
acme:
rp_id: 'example.com'
```
-{% endcode %}
Please note that all parameters are optional. The following configuration is perfectly valid. However, and as mentioned above, the parameter `id` is highly recommended.
-{% code title="app/config/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="app/config/webauthn.yaml" linenums="1"
webauthn:
request_profiles:
acme: ~
```
-{% endcode %}
diff --git a/symfony-bundle/entities-with-doctrine-1.md b/docs/symfony-bundle/entities-with-doctrine-1.md
similarity index 92%
rename from symfony-bundle/entities-with-doctrine-1.md
rename to docs/symfony-bundle/entities-with-doctrine-1.md
index 2990e83..076119d 100644
--- a/symfony-bundle/entities-with-doctrine-1.md
+++ b/docs/symfony-bundle/entities-with-doctrine-1.md
@@ -1,6 +1,6 @@
-# User Entity Repository
+# User entity repository
-## User Entity
+## User entity
Your application certainly has a user repository. Good news: there is no need to modify it!
@@ -10,8 +10,7 @@ This repository should be declared as a Symfony service and shall implement `Web
Hereafter an example where the application User Repository is injected. This repository uses Doctrine and provides `findOneBy*` methods.
-{% code title="src/Repository/WebauthnUserEntityRepository.php" lineNumbers="true" %}
-```php
+```php title="src/Repository/WebauthnUserEntityRepository.php" linenums="1"
<?php
+ We must override the method `saveCredentialSource` because we may receive `Webauthn\PublicKeyCredentialSource` objects instead of `App\Entity\WebauthnCredential`.
+
+```php title="App/Repository/WebauthnCredentialRepository.php" linenums="1" hl_lines="7"
+use App\Entity\WebauthnCredential;
-use Doctrine\Persistence\ManagerRegistry;
+use App\Entity\WebauthnCredential;
+use Doctrine\Persistence\ManagerRegistry;
use Webauthn\Bundle\Repository\DoctrineCredentialSourceRepository;
use Webauthn\PublicKeyCredentialSource;
@@ -144,18 +143,15 @@ final class WebauthnCredentialRepository extends DoctrineCredentialSourceReposit
parent::saveCredentialSource($publicKeyCredentialSource);
}
}
-
-
+```
This repository should be declared as a Symfony service.
-{% hint style="info" %}
-With Symfony autowiring and autoconfiguration, this is usually done automatically
-{% endhint %}
+!!! info
+
+ With Symfony autowiring and autoconfiguration, this is usually done automatically
-{% code title="config/services.yaml" %}
-```yaml
+```yaml title="config/services.yaml"
services:
App\Repository\WebauthnCredentialRepository: ~
```
-{% endcode %}
diff --git a/symfony-bundle/firewall.md b/docs/symfony-bundle/firewall.md
similarity index 89%
rename from symfony-bundle/firewall.md
rename to docs/symfony-bundle/firewall.md
index 3f9671f..4b3202f 100644
--- a/symfony-bundle/firewall.md
+++ b/docs/symfony-bundle/firewall.md
@@ -4,14 +4,13 @@ description: How to register and authenticate my users?
# Firewall
-## Security Bundle
+## Security bundle
To authenticate or register your users with Symfony, the best and easiest way is to use the Security Bundle. First, install that bundle and follow the instructions given by [the official documentation](https://symfony.com/doc/current/security.html).
At the end of the installation and configuration, you should have a `config/packages/security.yaml` file that looks like as follow:
-{% code title="config/packages/security.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/security.yaml" linenums="1"
security:
providers:
default:
@@ -22,7 +21,6 @@ security:
path: 'logout'
...
```
-{% endcode %}
## Controller
@@ -88,7 +86,7 @@ Below an example of a login form using the [Stimulus Controller](../symfony-ux/i
{% endblock %}
```
-## Login Authenticator
+## Login authenticator
Next, we need a Symfony Authenticator to handle login form submissions. With Webauthn, we use a dedicated Passport that shall contain a specific Badge.
@@ -145,12 +143,11 @@ final class LoginAuthenticator extends WebauthnAuthenticator
}
```
-## Security Configuration
+## Security configuration
To enable the user authentication, you just have to declare the Symfony Authenticator if the appropriate firewall (here `main`).
-{% code title="config/packages/security.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/security.yaml" linenums="1"
security:
providers:
default:
@@ -164,16 +161,14 @@ security:
- { path: ^/login, roles: PUBLIC_ACCESS, requires_channel: 'https'}
- { path: ^/logout, roles: PUBLIC_ACCESS}
```
-{% endcode %}
-{% hint style="info" %}
-**Multiple User Providers (v5.2.1+):** The bundle now supports multiple user providers. If your application uses multiple providers, you can configure them in the security configuration and the WebauthnBadge will work correctly with all of them.
-{% endhint %}
+!!! info
+
+ **Multiple User Providers (v5.2.1+):** The bundle now supports multiple user providers. If your application uses multiple providers, you can configure them in the security configuration and the WebauthnBadge will work correctly with all of them.
Also, you need to define the credential options endpoint.
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -181,13 +176,12 @@ webauthn:
login:
options_path: '/login/webauthn/options'
```
-{% endcode %}
-## User Registration
+## User registration
TO BE WRITTEN
-## Authentication Attributes
+## Authentication attributes
The security token returned by the firewall sets some attributes depending on the assertion and the capabilities of the authenticator. The attributes are:
@@ -196,10 +190,8 @@ The security token returned by the firewall sets some attributes depending on th
You can then set constraints to the access controls. In the example below, the /admin path can be reached by users with the role `ROLE_ADMIN` and that **have been verified** during the ceremony.
-{% code title="config/packages/security.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/security.yaml" linenums="1"
security:
access_control:
- { path: ^/admin, roles: [ROLE_ADMIN, IS_USER_VERIFIED]}
```
-{% endcode %}
diff --git a/symfony-bundle/the-symfony-way.md b/docs/symfony-bundle/the-symfony-way.md
similarity index 62%
rename from symfony-bundle/the-symfony-way.md
rename to docs/symfony-bundle/the-symfony-way.md
index 70bcd6c..eef67d4 100644
--- a/symfony-bundle/the-symfony-way.md
+++ b/docs/symfony-bundle/the-symfony-way.md
@@ -1,12 +1,12 @@
-# Bundle Installation
+# Bundle installation
This framework provides a Symfony bundle that will help you to use the components within your Symfony application.
-{% hint style="info" %}
-Implementations for other frameworks and web applications exist.
+!!! info
-As an example if you use Laravel, you may be interested in [this project: https://github.com/asbiin/laravel-webauthn](https://github.com/asbiin/laravel-webauthn)
-{% endhint %}
+ Implementations for other frameworks and web applications exist.
+
+ As an example if you use Laravel, you may be interested in [this project: https://github.com/asbiin/laravel-webauthn](https://github.com/asbiin/laravel-webauthn)
## Installation
@@ -16,16 +16,15 @@ As an example if you use Laravel, you may be interested in [this project: https:
composer require web-auth/webauthn-symfony-bundle
```
-{% hint style="info" %}
-As the recipes are third party ones not officially supported by Symfony, you will be asked to execute the recipe or not. When applied, the recipes will prompt a message such as `WebAuthn Framework is ready.`
-{% endhint %}
+!!! info
+
+ As the recipes are third party ones not officially supported by Symfony, you will be asked to execute the recipe or not. When applied, the recipes will prompt a message such as `WebAuthn Framework is ready.`
### Without Symfony Flex
If you don't use Symfony Flex, you must register the bundle and route manually.
-{% code title="config/bundles.php" lineNumbers="true" %}
-```php
+```php title="config/bundles.php" linenums="1"
['all' => true],
];
```
-{% endcode %}
-{% code title="config/routes/webauthn.php" lineNumbers="true" %}
-```php
+```php title="config/routes/webauthn.php" linenums="1"
import('.', 'webauthn');
};
```
-{% endcode %}
## Repositories
diff --git a/symfony-ux/additional-authenticators.md b/docs/symfony-ux/additional-authenticators.md
similarity index 82%
rename from symfony-ux/additional-authenticators.md
rename to docs/symfony-ux/additional-authenticators.md
index a53f988..8962378 100644
--- a/symfony-ux/additional-authenticators.md
+++ b/docs/symfony-ux/additional-authenticators.md
@@ -1,8 +1,8 @@
-# Additional Authenticators
+# Additional authenticators
Users can register multiple authenticators to their account for backup purposes or to use different devices. This page explains how to manage multiple authenticators per user.
-## Why Multiple Authenticators?
+## Why multiple authenticators?
Allowing users to register multiple authenticators provides several benefits:
@@ -11,12 +11,11 @@ Allowing users to register multiple authenticators provides several benefits:
* **Device upgrades**: Smoothly transition when replacing devices
* **Shared accounts**: Family members can each use their own authenticator (if your security policy allows)
-## Listing User Authenticators
+## Listing user authenticators
Display all authenticators registered to the current user:
-{% code title="src/Controller/SecurityController.php" lineNumbers="true" %}
-```php
+```php title="src/Controller/SecurityController.php" linenums="1"
{% endblock %}
```
-{% endcode %}
-## Adding Additional Authenticators
+## Adding additional authenticators
Allow authenticated users to register additional authenticators:
-{% code title="templates/security/add_authenticator.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/security/add_authenticator.html.twig" linenums="1"
{% extends 'base.html.twig' %}
{% block body %}
@@ -135,18 +130,16 @@ Allow authenticated users to register additional authenticators:
{% endblock %}
```
-{% endcode %}
-{% hint style="info" %}
-The controller configuration for `add_device` should use `CurrentUserEntityGuesser` to automatically get the authenticated user. See the [User Registration](user-registration.md#configuration-for-existing-users) page for configuration details.
-{% endhint %}
+!!! info
-## Removing Authenticators
+ The controller configuration for `add_device` should use `CurrentUserEntityGuesser` to automatically get the authenticated user. See the [User Registration](user-registration.md#configuration-for-existing-users) page for configuration details.
+
+## Removing authenticators
Allow users to remove authenticators they no longer use:
-{% code title="src/Controller/SecurityController.php" lineNumbers="true" %}
-```php
+```php title="src/Controller/SecurityController.php" linenums="1"
#[Route('/security/authenticators/{id}/remove', name: 'app_remove_authenticator')]
#[IsGranted('ROLE_USER')]
public function removeAuthenticator(
@@ -177,23 +170,21 @@ public function removeAuthenticator(
return $this->redirectToRoute('app_list_authenticators');
}
```
-{% endcode %}
-{% hint style="warning" %}
-**Important Security Considerations:**
+!!! warning
+
+ **Important Security Considerations:**
-* Always verify the authenticator belongs to the current user before removal
-* Prevent users from removing their last authenticator (would lock them out)
-* Consider requiring re-authentication before removal for sensitive accounts
-* Log authenticator additions and removals for security auditing
-{% endhint %}
+ * Always verify the authenticator belongs to the current user before removal
+ * Prevent users from removing their last authenticator (would lock them out)
+ * Consider requiring re-authentication before removal for sensitive accounts
+ * Log authenticator additions and removals for security auditing
-## Naming Authenticators
+## Naming authenticators
Allow users to give friendly names to their authenticators for easier management:
-{% code title="src/Entity/WebauthnCredential.php" lineNumbers="true" %}
-```php
+```php title="src/Entity/WebauthnCredential.php" linenums="1"
use Doctrine\ORM\Mapping as ORM;
use Webauthn\PublicKeyCredentialSource;
@@ -231,12 +222,10 @@ class WebauthnCredential extends PublicKeyCredentialSource
// ... other methods
}
```
-{% endcode %}
Then allow users to set names during or after registration:
-{% code title="templates/security/add_authenticator.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/security/add_authenticator.html.twig" linenums="1"
```
-{% endcode %}
-## Best Practices
+## Best practices
-### Encourage Backup Authenticators
+### Encourage backup authenticators
Prompt users to register a backup authenticator after their first registration:
-{% code lineNumbers="true" %}
-```twig
+```twig linenums="1"
{% if credential_count == 1 %}
Add a backup authenticator!
@@ -270,9 +257,8 @@ Prompt users to register a backup authenticator after their first registration:
{% endif %}
```
-{% endcode %}
-### Authenticator Metadata
+### Authenticator metadata
Display useful information about each authenticator:
@@ -281,14 +267,14 @@ Display useful information about each authenticator:
* **Registration date**: Track when each authenticator was added
* **AAGUID**: Identify the authenticator model (if available)
-### Security Recommendations
+### Security recommendations
* **Minimum authenticators**: Consider requiring at least 2 authenticators for privileged accounts
* **Maximum authenticators**: Limit to prevent abuse (e.g., 10 per user)
* **Inactive authenticators**: Automatically remove authenticators not used for a long period
* **Notification**: Email users when authenticators are added or removed
-## See Also
+## See also
* [User Registration](user-registration.md) - Register the first authenticator
* [User Authentication](integration.md) - Authenticate with any registered authenticator
diff --git a/symfony-ux/installation.md b/docs/symfony-ux/installation.md
similarity index 87%
rename from symfony-ux/installation.md
rename to docs/symfony-ux/installation.md
index c824be3..ee3a143 100644
--- a/symfony-ux/installation.md
+++ b/docs/symfony-ux/installation.md
@@ -7,7 +7,7 @@ The [Symfony UX Initiative](https://symfony.com/ux) enables high-interaction app
Before installing the Stimulus Controller, you need:
1. **Symfony UX configured** - Follow the [official Symfony UX documentation](https://symfony.com/doc/current/frontend/ux.html)
-2. **WebAuthn Bundle installed** - See [Symfony Bundle Installation](the-symfony-way.md)
+2. **WebAuthn Bundle installed** - See [Symfony Bundle Installation](../symfony-bundle/the-symfony-way.md)
## Installation
@@ -22,16 +22,15 @@ This command will automatically:
* Register the Stimulus controller via Symfony Flex
* Configure AssetMapper to import the necessary JavaScript files
-{% hint style="info" %}
-**No build step required!** The package works with Symfony AssetMapper, so you don't need Node.js, npm, yarn, or any JavaScript build tools. The browser imports the JavaScript files directly.
-{% endhint %}
+!!! info
-## Verify Installation
+ **No build step required!** The package works with Symfony AssetMapper, so you don't need Node.js, npm, yarn, or any JavaScript build tools. The browser imports the JavaScript files directly.
+
+## Verify installation
Check that the Stimulus controller is properly registered in your `assets/controllers.json`:
-{% code title="assets/controllers.json" lineNumbers="true" %}
-```json
+```json title="assets/controllers.json" linenums="1"
{
"controllers": {
"@web-auth/webauthn-stimulus": {
@@ -40,9 +39,8 @@ Check that the Stimulus controller is properly registered in your `assets/contro
}
}
```
-{% endcode %}
-## What's Included
+## What's included
The package provides a Stimulus controller that handles:
@@ -52,17 +50,16 @@ The package provides a Stimulus controller that handles:
* **Error handling** - Gracefully handles common WebAuthn errors
* **Browser autofill** - Supports conditional UI for passkey selection
-## Basic Usage
+## Basic usage
Once installed, you can use the Stimulus controller in your Twig templates with two simple functions:
1. **`stimulus_controller()`** - Attach the controller to your form
2. **`stimulus_action()`** - Trigger WebAuthn operations on button clicks
-### Registration Form Example
+### Registration form example
-{% code title="templates/registration/register.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/registration/register.html.twig" linenums="1"
```
-{% endcode %}
-### Authentication Form Example
+### Authentication form example
-{% code title="templates/security/login.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/security/login.html.twig" linenums="1"
```
-{% endcode %}
-## Controller Options
+## Controller options
The Stimulus controller accepts various configuration options:
-### Registration Options
+### Registration options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `creationOptionsUrl` | string | Yes | URL endpoint that returns `PublicKeyCredentialCreationOptions` |
| `creationResultField` | string | Yes | CSS selector for hidden field to store attestation response |
-### Authentication Options
+### Authentication options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
@@ -128,12 +122,11 @@ The Stimulus controller accepts various configuration options:
| `requestResultField` | string | Yes | CSS selector for hidden field to store assertion response |
| `useBrowserAutofill` | boolean | No | Enable conditional UI for browser autofill (default: false) |
-## Testing Your Installation
+## Testing your installation
Create a simple test page to verify everything works:
-{% code title="templates/test/webauthn.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/test/webauthn.html.twig" linenums="1"
{% extends 'base.html.twig' %}
{% block body %}
@@ -191,11 +184,10 @@ Create a simple test page to verify everything works:
{% endif %}
{% endblock %}
```
-{% endcode %}
## Troubleshooting
-### Controller Not Found
+### Controller not found
If you see "Controller '@web-auth/webauthn-stimulus' not found":
@@ -203,7 +195,7 @@ If you see "Controller '@web-auth/webauthn-stimulus' not found":
2. Clear Symfony cache: `php bin/console cache:clear`
3. Check that AssetMapper is properly configured in `config/packages/asset_mapper.yaml`
-### JavaScript Errors
+### JavaScript errors
If you see console errors:
@@ -212,7 +204,7 @@ If you see console errors:
3. Verify WebAuthn routes are properly configured in `config/routes/webauthn.yaml`
4. Ensure the controller is loaded by checking the browser's network tab
-### Assets Not Loading
+### Assets not loading
If the Stimulus controller doesn't load:
@@ -225,7 +217,7 @@ If the Stimulus controller doesn't load:
2. Check that Stimulus is properly configured in your application
-## HTTPS Requirement
+## HTTPS requirement
WebAuthn **requires HTTPS** to function. For development, use the Symfony CLI for automatic HTTPS:
@@ -236,7 +228,7 @@ symfony serve
For production, ensure HTTPS is properly configured on your web server.
-## Next Steps
+## Next steps
Now that the Stimulus Controller is installed, proceed to:
@@ -244,9 +236,9 @@ Now that the Stimulus Controller is installed, proceed to:
2. **[User Authentication](integration.md)** - Implement login flows
3. **[Additional Authenticators](additional-authenticators.md)** - Allow users to register backup devices
-## See Also
+## See also
* [Symfony UX Documentation](https://symfony.com/doc/current/frontend/ux.html) - Official UX guide
* [Stimulus Documentation](https://stimulus.hotwired.dev/) - Stimulus framework reference
-* [WebAuthn Bundle](the-symfony-way.md) - Backend configuration
+* [WebAuthn Bundle](../symfony-bundle/the-symfony-way.md) - Backend configuration
* [JavaScript Integration](../prerequisites/javascript.md) - Manual JavaScript implementation
diff --git a/symfony-ux/integration.md b/docs/symfony-ux/integration.md
similarity index 98%
rename from symfony-ux/integration.md
rename to docs/symfony-ux/integration.md
index 2f26e7c..7ab533b 100644
--- a/symfony-ux/integration.md
+++ b/docs/symfony-ux/integration.md
@@ -1,4 +1,4 @@
-# User Authentication
+# User authentication
With the version 5.2 of the bundle, the login process is very similar to the username/password login.
@@ -54,7 +54,7 @@ The `requestResultField` parameter corresponds to the selector to the hidden fie
The behavior after the login is managed by your Symfony Security Authenticator.
-### Browser Autofill
+### Browser autofill
When authenticators are available on the device and the browser is aware of them, you can simplify the way users will sign in. When this feature is enabled, the user will see the list of available authenticators when focusing on the username field. Selecting an account in the list will automatically perform the authentication actions. There is a simple option to enable this feature:
diff --git a/symfony-ux/user-registration.md b/docs/symfony-ux/user-registration.md
similarity index 78%
rename from symfony-ux/user-registration.md
rename to docs/symfony-ux/user-registration.md
index d2e9796..00026c3 100644
--- a/symfony-ux/user-registration.md
+++ b/docs/symfony-ux/user-registration.md
@@ -1,20 +1,19 @@
-# User Registration
+# 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
+## 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
+### 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
-{% code title="templates/registration/register.html.twig" lineNumbers="true" %}
-```twig
+```twig title="templates/registration/register.html.twig" linenums="1"
```
-{% endcode %}
-### Bundle Configuration
+### Bundle configuration
Configure the bundle to handle new user registration:
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
credential_repository: 'App\Repository\WebauthnCredentialRepository'
user_repository: 'App\Repository\UserRepository'
@@ -72,14 +69,12 @@ webauthn:
result_path: '/register/webauthn'
user_entity_guesser: 'App\Guesser\NewUserEntityGuesser'
```
-{% endcode %}
-### User Entity Guesser
+### User entity guesser
Create a guesser to handle new user registration:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
```
-{% endcode %}
-### Configuration for Existing Users
+### Configuration for existing users
-{% code title="config/packages/webauthn.yaml" lineNumbers="true" %}
-```yaml
+```yaml title="config/packages/webauthn.yaml" linenums="1"
webauthn:
controllers:
enabled: true
@@ -157,13 +148,12 @@ webauthn:
result_path: '/devices/add'
user_entity_guesser: 'Webauthn\Bundle\Security\Guesser\CurrentUserEntityGuesser'
```
-{% endcode %}
-{% hint style="success" %}
-The `CurrentUserEntityGuesser` automatically retrieves the currently authenticated user from the Symfony security context. No custom guesser needed!
-{% endhint %}
+!!! success
+
+ The `CurrentUserEntityGuesser` automatically retrieves the currently authenticated user from the Symfony security context. No custom guesser needed!
-## Stimulus Controller Options
+## Stimulus controller options
The registration controller accepts the following options:
@@ -173,12 +163,11 @@ The registration controller accepts the following 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
+### Auto-register example
Automatically start the registration process when the page loads:
-{% code lineNumbers="true" %}
-```twig
+```twig linenums="1"
{{ stimulus_controller('@web-auth/webauthn-stimulus',
{
autoRegister: true,
@@ -187,18 +176,16 @@ Automatically start the registration process when the page loads:
}
) }}
```
-{% endcode %}
-{% hint style="warning" %}
-Use `autoRegister` carefully as it immediately prompts the user for biometric authentication or security key interaction.
-{% endhint %}
+!!! warning
+
+ Use `autoRegister` carefully as it immediately prompts the user for biometric authentication or security key interaction.
-## Error Handling
+## Error handling
Handle registration errors in your custom event listeners:
-{% code lineNumbers="true" %}
-```javascript
+```javascript linenums="1"
document.addEventListener('webauthn:registration:error', (event) => {
console.error('Registration failed:', event.detail);
alert('Could not register authenticator: ' + event.detail.message);
@@ -208,9 +195,8 @@ document.addEventListener('webauthn:registration:success', (event) => {
console.log('Registration successful!');
});
```
-{% endcode %}
-## See Also
+## See also
* [User Authentication](integration.md) - Authenticate users with registered authenticators
* [Additional Authenticators](additional-authenticators.md) - Manage multiple authenticators
diff --git a/the-project/contributing.md b/docs/the-project/contributing.md
similarity index 100%
rename from the-project/contributing.md
rename to docs/the-project/contributing.md
diff --git a/the-project/installation.md b/docs/the-project/installation.md
similarity index 100%
rename from the-project/installation.md
rename to docs/the-project/installation.md
diff --git a/the-project/the-project.md b/docs/the-project/the-project.md
similarity index 83%
rename from the-project/the-project.md
rename to docs/the-project/the-project.md
index 370be55..19d3414 100644
--- a/the-project/the-project.md
+++ b/docs/the-project/the-project.md
@@ -10,7 +10,7 @@ The complete specification can be found on [the W3C dedicated page](https://www.
This framework contains PHP libraries and Symfony bundle to allow developers to integrate that authentication mechanism into their web applications.
-## Class, Constant and Property Names
+## Class, constant and property names
Naming things may be complicated. That’s why the following rule applies on the whole framework: the name of classes, constants and properties are identical to the ones you will find in the specification.
@@ -46,15 +46,15 @@ As an example, the [section 5.2.2 “Web Authentication Assertion”](https://ww
* Supported (not fully tested)
* appid extension (compatibility with FIDO U2F authenticator
-## Compatible Authenticators
+## Compatible authenticators
As of January 2023, our framework supports every authenticator with full feature and algorithm support, achieving a 100% success rate across all tests. Official FIDO Alliance testing tools have validated its compliance.
We ensure continuous conformity through rigorous unit and functional testing throughout the development process.
-{% hint style="info" %}
-See [https://github.com/herrjemand/awesome-webauthn/pull/61](https://github.com/herrjemand/awesome-webauthn/pull/61) and [https://github.com/herrjemand/awesome-webauthn#server-libs](https://github.com/herrjemand/awesome-webauthn?#server-libraries)
-{% endhint %}
+!!! info
+
+ See [https://github.com/herrjemand/awesome-webauthn/pull/61](https://github.com/herrjemand/awesome-webauthn/pull/61) and [https://github.com/herrjemand/awesome-webauthn#server-libs](https://github.com/herrjemand/awesome-webauthn?#server-libraries)
## Support
@@ -70,6 +70,6 @@ If you feel comfortable writing code, you could try to fix [opened issues where
Do not forget to follow [these best practices](contributing.md).
-{% hint style="danger" %}
-If you think you have found a security issue, **DO NOT open an issue**. [You MUST submit your issue here](https://github.com/web-auth/webauthn-framework/security).
-{% endhint %}
+!!! danger
+
+ If you think you have found a security issue, **DO NOT open an issue**. [You MUST submit your issue here](https://github.com/web-auth/webauthn-framework/security).
diff --git a/the-project/web-browser-support.md b/docs/the-project/web-browser-support.md
similarity index 95%
rename from the-project/web-browser-support.md
rename to docs/the-project/web-browser-support.md
index cb573e6..a0bb641 100644
--- a/the-project/web-browser-support.md
+++ b/docs/the-project/web-browser-support.md
@@ -2,7 +2,7 @@
description: Adoption by web browsers
---
-# Web Browser Support
+# Web browser support
Webauthn is now supported by all main web browsers:
diff --git a/webauthn-in-a-nutshell/attestation-and-metadata-statement.md b/docs/webauthn-in-a-nutshell/attestation-and-metadata-statement.md
similarity index 68%
rename from webauthn-in-a-nutshell/attestation-and-metadata-statement.md
rename to docs/webauthn-in-a-nutshell/attestation-and-metadata-statement.md
index 265a90c..e0f1675 100644
--- a/webauthn-in-a-nutshell/attestation-and-metadata-statement.md
+++ b/docs/webauthn-in-a-nutshell/attestation-and-metadata-statement.md
@@ -1,14 +1,14 @@
-# Metadata Statement
+# Metadata statement
-{% hint style="info" %}
-This page is about an advanced feature. You can skip it if you are new with Webauthn
-{% endhint %}
+!!! info
-{% hint style="danger" %}
-Disclaimer: you **should not** ask for the Attestation Statement unless you want to play with it or you are working on an application that requires a high level of trust (e.g. Banking/Financial Company, Government Agency...).
-{% endhint %}
+ This page is about an advanced feature. You can skip it if you are new with Webauthn
-## Attestation Statement
+!!! danger
+
+ Disclaimer: you **should not** ask for the Attestation Statement unless you want to play with it or you are working on an application that requires a high level of trust (e.g. Banking/Financial Company, Government Agency...).
+
+## Attestation statement
During the Attestation Ceremony (i.e. the registration of the authenticator), you can ask for the Attestation Statement of the authenticator. The Attestation Statements have one of the following types:
@@ -18,12 +18,12 @@ During the Attestation Ceremony (i.e. the registration of the authenticator), yo
* **Attestation CA** (`AttCA`): Authenticators are based on a Trusted Platform Module (TPM). They can generate multiple attestation identity key pairs (AIK) and requests an Attestation CA to issue an AIK certificate for each.
* **Anonymization CA** (`AnonCA`): Authenticators use an Anonymization CA, which dynamically generates per-credential attestation certificates such that the attestation statements presented to Relying Parties do not provide uniquely identifiable information.
-## Metadata Statement
+## Metadata statement
The Metadata Statements are issued by the manufacturers of the authenticators. These statements contain details about the authenticators (supported algorithms, biometric capabilities...) and all the necessary information to verify the Attestation Statements generated during the attestation ceremony.
There are several possible sources to get these Metadata Statements. The main source is the [FIDO Alliance Metadata Service](https://fidoalliance.org/metadata) that allows fetching statements on-demand, but some of them may be provided by other means.
-{% hint style="danger" %}
-The FIDO Alliance Metadata Service provides a limited number of Metadata Statements. It is mandatory to get the statement from the manufacturer of your authenticators otherwise the Attestation Statement won't be verified and the Attestation Ceremony will fail.
-{% endhint %}
+!!! danger
+
+ The FIDO Alliance Metadata Service provides a limited number of Metadata Statements. It is mandatory to get the statement from the manufacturer of your authenticators otherwise the Attestation Statement won't be verified and the Attestation Ceremony will fail.
diff --git a/webauthn-in-a-nutshell/authenticators.md b/docs/webauthn-in-a-nutshell/authenticators.md
similarity index 74%
rename from webauthn-in-a-nutshell/authenticators.md
rename to docs/webauthn-in-a-nutshell/authenticators.md
index 5213a4c..57fa60f 100644
--- a/webauthn-in-a-nutshell/authenticators.md
+++ b/docs/webauthn-in-a-nutshell/authenticators.md
@@ -8,27 +8,30 @@ An Authenticator is a cryptographic entity used to generate a public key credent
Authenticators may have additional features such as PIN code or biometric sensors (fingerprint, facial recognition…) that offer user verification.
-.jpeg>)
+
-## Roaming Authenticators
+## Roaming authenticators
The roaming authenticator may have different forms. The most common form is a USB device the user plugs into its computer. It can be a paired Bluetooth device or a card with NFC capabilities.
Authenticators of this class are removable from, and can "roam" among, client devices.
-
+
-## Platform Authenticators
+## Platform authenticators
A platform authenticator is usually not removable from the client device. For example an Android smartphone or a Windows 10 computer with the associated security chips can act as an authenticator.
-.png>)
+
-
+
### Passkey
-
Passkey Logo
+
+ { width="188" }
+ Passkey Logo
+
Passkey are virtual authenticators that have extended capabilities and in particular:
diff --git a/webauthn-in-a-nutshell/ceremonies.md b/docs/webauthn-in-a-nutshell/ceremonies.md
similarity index 84%
rename from webauthn-in-a-nutshell/ceremonies.md
rename to docs/webauthn-in-a-nutshell/ceremonies.md
index ec989d9..d7f1543 100644
--- a/webauthn-in-a-nutshell/ceremonies.md
+++ b/docs/webauthn-in-a-nutshell/ceremonies.md
@@ -6,11 +6,11 @@ description: Registration and Authentication process overview
In WebAuthn, authentication workflows are called "ceremonies" - a term that emphasizes the formal, cryptographic nature of these operations. There are two main ceremonies that form the foundation of WebAuthn authentication.
-## The Two Ceremonies
+## The two ceremonies
WebAuthn defines two distinct ceremonies:
-### 1. Attestation Ceremony (Registration)
+### 1. Attestation ceremony (registration)
**Also called:** Creation Ceremony, Registration Ceremony
@@ -21,7 +21,7 @@ WebAuthn defines two distinct ceremonies:
* Adding an additional authenticator to an existing account
* Registering a backup security key
-### 2. Assertion Ceremony (Authentication)
+### 2. Assertion ceremony (authentication)
**Also called:** Request Ceremony, Authentication Ceremony, Login Ceremony
@@ -32,11 +32,11 @@ WebAuthn defines two distinct ceremonies:
* Step-up authentication for sensitive operations
* Re-authentication after session timeout
-## Common Workflow Pattern
+## Common workflow pattern
Both ceremonies follow a similar two-step pattern:
-### Step 1: Options Creation
+### Step 1: Options creation
The Relying Party (your server) creates options that:
* Define parameters for the operation
@@ -44,7 +44,7 @@ The Relying Party (your server) creates options that:
* Specify requirements and preferences
* Are sent to the browser/authenticator
-### Step 2: Response Verification
+### Step 2: Response verification
The authenticator:
* Prompts the user for interaction
@@ -52,22 +52,21 @@ The authenticator:
* Returns a signed response
* The server validates the response
-{% hint style="info" %}
-User interaction varies based on authenticator capabilities and your configuration. It can range from a simple button touch to biometric authentication (fingerprint, facial recognition, PIN code).
-{% endhint %}
+!!! info
-## Attestation Ceremony (Registration)
+ User interaction varies based on authenticator capabilities and your configuration. It can range from a simple button touch to biometric authentication (fingerprint, facial recognition, PIN code).
+
+## Attestation ceremony (registration)
The attestation ceremony registers a new authenticator credential for a user.
-.png>)
+
-### Attestation Flow Breakdown
+### Attestation flow breakdown
-#### Server Side (Step 1)
+#### Server side (step 1)
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// 1. Create PublicKeyCredentialCreationOptions
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create(
rp: $rpEntity, // Your application identity
@@ -83,9 +82,8 @@ $session->set('webauthn_creation_challenge', $publicKeyCredentialCreationOptions
// 3. Send options to browser as JSON
return new JsonResponse($publicKeyCredentialCreationOptions);
```
-{% endcode %}
-#### Client Side (Browser)
+#### Client side (browser)
```javascript
// 1. Receive options from server
@@ -103,10 +101,9 @@ await fetch('/webauthn/register', {
});
```
-#### Server Side (Step 2)
+#### Server side (step 2)
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// 1. Load the attestation response
$publicKeyCredential = $serializer->deserialize(
$request->getContent(),
@@ -124,9 +121,8 @@ $credentialSource = $attestationValidator->check(
// 3. Save the new credential
$credentialRepository->saveCredentialSource($credentialSource);
```
-{% endcode %}
-### What Happens During Attestation?
+### What happens during attestation?
1. **Challenge Generation**: Server creates a random challenge to prevent replay attacks
2. **User Prompt**: Browser asks user to interact with authenticator
@@ -135,7 +131,7 @@ $credentialRepository->saveCredentialSource($credentialSource);
5. **Verification**: Server verifies signatures and stores the public key
6. **Storage**: Credential is saved and associated with the user account
-### Attestation Data Contains
+### Attestation data contains
* **Public Key**: Used to verify future signatures
* **Credential ID**: Unique identifier for this credential
@@ -143,18 +139,17 @@ $credentialRepository->saveCredentialSource($credentialSource);
* **Signature Counter**: Used to detect cloned authenticators
* **Attestation Statement**: Optional proof of authenticator authenticity
-## Assertion Ceremony (Authentication)
+## Assertion ceremony (authentication)
The assertion ceremony authenticates a user with a previously registered credential.
-
+
-### Assertion Flow Breakdown
+### Assertion flow breakdown
-#### Server Side (Step 1)
+#### Server side (step 1)
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// 1. Get user's registered credentials
$credentials = $credentialRepository->findAllForUserEntity($userEntity);
$allowedCredentials = array_map(
@@ -175,9 +170,8 @@ $session->set('webauthn_request_challenge', $publicKeyCredentialRequestOptions->
// 4. Send options to browser
return new JsonResponse($publicKeyCredentialRequestOptions);
```
-{% endcode %}
-#### Client Side (Browser)
+#### Client side (browser)
```javascript
// 1. Receive options from server
@@ -195,10 +189,9 @@ await fetch('/webauthn/login', {
});
```
-#### Server Side (Step 2)
+#### Server side (step 2)
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// 1. Load the assertion response
$publicKeyCredential = $serializer->deserialize(
$request->getContent(),
@@ -226,9 +219,8 @@ $credentialRepository->saveCredentialSource($updatedCredential);
// 5. Log the user in
$session->set('user_id', $userEntity->id);
```
-{% endcode %}
-### What Happens During Assertion?
+### What happens during assertion?
1. **Challenge Generation**: Server creates a new random challenge
2. **Credential Selection**: Browser identifies available credentials
@@ -238,14 +230,14 @@ $session->set('user_id', $userEntity->id);
6. **Counter Check**: Server verifies counter to detect cloning
7. **Authentication**: If valid, user is logged in
-### Assertion Data Contains
+### Assertion data contains
* **Authenticator Data**: Flags, counter, extensions
* **Client Data**: Origin, challenge, type
* **Signature**: Cryptographic proof using the private key
* **User Handle**: Optional user identifier (for usernameless authentication)
-## Key Differences Between Ceremonies
+## Key differences between ceremonies
| Aspect | Attestation (Registration) | Assertion (Authentication) |
|--------|---------------------------|---------------------------|
@@ -257,14 +249,13 @@ $session->set('user_id', $userEntity->id);
| **Validator Class** | `AuthenticatorAttestationResponseValidator` | `AuthenticatorAssertionResponseValidator` |
| **User Experience** | "Register security key" | "Use security key to sign in" |
-## Security Considerations
+## Security considerations
-### Challenge Uniqueness
+### Challenge uniqueness
Both ceremonies require a unique, random challenge:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Always generate a fresh challenge
$challenge = random_bytes(32); // 32 bytes = 256 bits of entropy
@@ -272,14 +263,12 @@ $challenge = random_bytes(32); // 32 bytes = 256 bits of entropy
// NEVER use predictable challenges (like timestamps)
// NEVER skip challenge verification
```
-{% endcode %}
-### Challenge Storage
+### Challenge storage
Store challenges temporarily in server-side sessions:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Store during Step 1 (options creation)
$session->set('webauthn_challenge', base64_encode($challenge));
$session->set('webauthn_challenge_expires', time() + 60); // 60 second timeout
@@ -292,14 +281,12 @@ if (time() > $session->get('webauthn_challenge_expires')) {
throw new \Exception('Challenge expired');
}
```
-{% endcode %}
-### Origin Validation
+### Origin validation
Always verify the origin matches your domain:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Server must verify origin during validation
$credentialSource = $attestationValidator->check(
$publicKeyCredential->response,
@@ -307,18 +294,17 @@ $credentialSource = $attestationValidator->check(
'https://example.com' // Must match your actual domain
);
```
-{% endcode %}
-## Common Pitfalls
+## Common pitfalls
-### ❌ Challenge Reuse
+### ❌ Challenge reuse
```php
// WRONG: Reusing the same challenge
$challenge = 'my-static-challenge'; // Never do this!
```
-### ❌ Skipping Verification
+### ❌ Skipping verification
```php
// WRONG: Trusting client data without validation
@@ -326,7 +312,7 @@ $credentialId = $_POST['credentialId'];
$user = $userRepository->find($credentialId); // DON'T!
```
-### ❌ Incorrect Origin
+### ❌ Incorrect origin
```php
// WRONG: Verifying with wrong domain
@@ -334,14 +320,13 @@ $attestationValidator->check($response, $options, 'http://localhost');
// But the actual domain is https://example.com
```
-## Best Practices
+## Best practices
-### ✅ Use Timeouts
+### ✅ Use timeouts
Set reasonable timeouts for user interaction:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create(
rp: $rpEntity,
user: $userEntity,
@@ -349,14 +334,12 @@ $publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create
timeout: 60000 // 60 seconds in milliseconds
);
```
-{% endcode %}
-### ✅ Handle Errors Gracefully
+### ✅ Handle errors gracefully
Provide helpful error messages:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
try {
$credentialSource = $attestationValidator->check(/* ... */);
} catch (\Webauthn\Exception\InvalidDataException $e) {
@@ -366,22 +349,19 @@ try {
], 400);
}
```
-{% endcode %}
-### ✅ Store Credential Metadata
+### ✅ Store credential metadata
Keep track of when and how credentials were registered:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$credential->createdAt = new \DateTimeImmutable();
$credential->lastUsedAt = null;
$credential->name = 'My YubiKey'; // Allow users to name their keys
$credential->transports = ['usb', 'nfc']; // Store transport hints
```
-{% endcode %}
-## See Also
+## See also
* [Authenticators](authenticators.md) - Learn about different authenticator types
* [User Verification](user-verification.md) - Understand UP vs UV flags
diff --git a/webauthn-in-a-nutshell/extensions.md b/docs/webauthn-in-a-nutshell/extensions.md
similarity index 81%
rename from webauthn-in-a-nutshell/extensions.md
rename to docs/webauthn-in-a-nutshell/extensions.md
index 69b84f2..f8c1ee3 100644
--- a/webauthn-in-a-nutshell/extensions.md
+++ b/docs/webauthn-in-a-nutshell/extensions.md
@@ -1,12 +1,12 @@
# Extensions
-{% hint style="info" %}
-This page is about an advanced feature. You can skip it if you are new with WebAuthn.
-{% endhint %}
+!!! info
+
+ This page is about an advanced feature. You can skip it if you are new with WebAuthn.
WebAuthn extensions are optional features that extend the core WebAuthn specification to support additional use cases and capabilities. They allow authenticators and browsers to provide extra functionality beyond basic authentication.
-## What Are Extensions?
+## What are extensions?
Extensions provide a standardized way to:
@@ -15,20 +15,20 @@ Extensions provide a standardized way to:
* Enable specific features like credential protection or large blob storage
* Maintain backward compatibility with legacy systems (like U2F)
-## How Extensions Work
+## How extensions work
Extensions work in both directions:
1. **Extension Inputs** - Sent from the Relying Party to the authenticator via the browser
2. **Extension Outputs** - Returned from the authenticator to the Relying Party after processing
-{% hint style="warning" %}
-**Important**: Authenticators may ignore extension inputs if they don't support them. Extension outputs are **not guaranteed** and your application should handle their absence gracefully.
-{% endhint %}
+!!! warning
+
+ **Important**: Authenticators may ignore extension inputs if they don't support them. Extension outputs are **not guaranteed** and your application should handle their absence gracefully.
-## Common WebAuthn Extensions
+## Common WebAuthn extensions
-### Standard Extensions
+### Standard extensions
The most commonly used WebAuthn extensions include:
@@ -49,7 +49,7 @@ All standard extensions are listed in the **IANA WebAuthn Extensions Registry**:
[https://www.iana.org/assignments/webauthn/webauthn.xhtml](https://www.iana.org/assignments/webauthn/webauthn.xhtml)
-## Library Support
+## Library support
This library provides:
@@ -57,16 +57,15 @@ This library provides:
* ✅ **AppID extension** - Built-in support for U2F backward compatibility
* ⚠️ **Custom extensions** - You need to implement extension handlers for other extensions
-{% hint style="warning" %}
-Most extensions require custom implementation. It is up to you to create the extension handlers depending on which extensions you want to support.
-{% endhint %}
+!!! warning
-## Basic Usage Example
+ Most extensions require custom implementation. It is up to you to create the extension handlers depending on which extensions you want to support.
+
+## Basic usage example
Here's how to add an extension input when creating credential options:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
response->getAuthenticatorData()->extensions;
@@ -103,16 +100,14 @@ if (isset($extensionOutputs['credProps']['rk'])) {
echo $isDiscoverable ? 'Resident key created' : 'Non-resident key';
}
```
-{% endcode %}
-## Practical Use Cases
+## Practical use cases
-### 1. U2F Migration (appid Extension)
+### 1. U2F migration (appid extension)
Allow existing U2F credentials to work with your WebAuthn implementation:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$extensions = AuthenticationExtensions::create([
AuthenticationExtension::create('appid', 'https://example.com')
]);
@@ -122,14 +117,12 @@ $publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
extensions: $extensions
);
```
-{% endcode %}
-### 2. Credential Properties (credProps Extension)
+### 2. Credential properties (credProps extension)
Determine if a credential supports resident keys (usernameless authentication):
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$extensions = AuthenticationExtensions::create([
AuthenticationExtension::create('credProps', true)
]);
@@ -137,14 +130,12 @@ $extensions = AuthenticationExtensions::create([
// After registration, check:
$rk = $extensionOutputs['credProps']['rk'] ?? false;
```
-{% endcode %}
-### 3. Large Blob Storage (largeBlob Extension)
+### 3. Large blob storage (largeBlob extension)
Store additional encrypted data with the credential:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Write blob during registration
$extensions = AuthenticationExtensions::create([
AuthenticationExtension::create('largeBlob', [
@@ -153,18 +144,16 @@ $extensions = AuthenticationExtensions::create([
])
]);
```
-{% endcode %}
-### 4. Pseudo-Random Function (prf Extension)
+### 4. Pseudo-random function (prf extension)
+
+!!! info
-{% hint style="info" %}
-PRF extension support was added in version 5.2.0
-{% endhint %}
+ PRF extension support was added in version 5.2.0
The PRF (Pseudo-Random Function) extension allows you to generate cryptographic keys from authenticator secrets. This is particularly useful for encryption scenarios:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Request PRF during authentication
$extensions = AuthenticationExtensions::create([
AuthenticationExtension::create('prf', [
@@ -179,11 +168,10 @@ $publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
extensions: $extensions
);
```
-{% endcode %}
-## Implementation Considerations
+## Implementation considerations
-### Check Extension Support
+### Check extension support
Not all authenticators support all extensions. Always:
@@ -191,7 +179,7 @@ Not all authenticators support all extensions. Always:
2. Have fallback behavior when extensions aren't supported
3. Don't rely on extensions for critical security features
-### Custom Extension Handlers
+### Custom extension handlers
For extensions beyond `appid`, you'll need to implement:
@@ -200,7 +188,7 @@ For extensions beyond `appid`, you'll need to implement:
See the [Pure PHP Extensions Guide](../pure-php/advanced-behaviours/extensions.md) or [Symfony Bundle Extensions Guide](../symfony-bundle/advanced-behaviors/extensions.md) for detailed implementation instructions.
-## When to Use Extensions
+## When to use extensions
Use extensions when you need:
@@ -215,7 +203,7 @@ Avoid extensions if:
* ❌ You need universal compatibility (not all devices support extensions)
* ❌ You're just getting started with WebAuthn
-## See Also
+## See also
* [Pure PHP Extensions Implementation](../pure-php/advanced-behaviours/extensions.md) - Detailed extension implementation
* [Symfony Extensions Configuration](../symfony-bundle/advanced-behaviors/extensions.md) - Framework-specific setup
diff --git a/webauthn-in-a-nutshell/user-verification.md b/docs/webauthn-in-a-nutshell/user-verification.md
similarity index 88%
rename from webauthn-in-a-nutshell/user-verification.md
rename to docs/webauthn-in-a-nutshell/user-verification.md
index 2c17c37..64fe9a0 100644
--- a/webauthn-in-a-nutshell/user-verification.md
+++ b/docs/webauthn-in-a-nutshell/user-verification.md
@@ -2,11 +2,11 @@
description: Prove to me who you claim to be!
---
-# User Verification
+# User verification
User verification is a WebAuthn feature that confirms the identity of the actual user, not just possession of the authenticator. It answers the question: "Is the person using this authenticator really the authorized user?"
-## What is User Verification?
+## What is user verification?
User verification requires the user to prove their identity through:
@@ -17,7 +17,7 @@ User verification requires the user to prove their identity through:
The goal is to **distinguish individual users** and ensure that the person authenticating is the legitimate account owner, not just someone who stole or found the authenticator.
-## User Presence vs User Verification
+## User presence vs user verification
It's important to understand the difference:
@@ -33,7 +33,7 @@ It's important to understand the difference:
**User Verification** goes further by confirming the specific identity of that person.
-## User Verification Requirements
+## User verification requirements
You can configure the user verification requirement when creating credential options. There are three possible values:
@@ -41,8 +41,7 @@ You can configure the user verification requirement when creating credential opt
The operation **requires** user verification and will **fail** if the authenticator does not set the `UV` flag.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
@@ -57,7 +56,6 @@ $publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create
authenticatorSelection: $authenticatorSelection
);
```
-{% endcode %}
**Use when:**
* High-security applications (banking, healthcare)
@@ -68,13 +66,11 @@ $publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create
The operation **prefers** user verification but will **not fail** if the authenticator doesn't provide it.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$authenticatorSelection = AuthenticatorSelectionCriteria::create(
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED
);
```
-{% endcode %}
This is the **recommended default** for most applications. It uses user verification when available but doesn't exclude authenticators that don't support it.
@@ -87,13 +83,11 @@ This is the **recommended default** for most applications. It uses user verifica
The operation **discourages** user verification to minimize disruption to the user flow.
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
$authenticatorSelection = AuthenticatorSelectionCriteria::create(
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_DISCOURAGED
);
```
-{% endcode %}
**Use when:**
* Low-risk operations
@@ -101,12 +95,11 @@ $authenticatorSelection = AuthenticatorSelectionCriteria::create(
* Simple presence verification is sufficient
* Testing or demonstration purposes
-## Checking the UV Flag
+## Checking the UV flag
After authentication or registration, verify whether user verification actually occurred:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// During assertion validation
$authenticatorData = $publicKeyCredential->response->getAuthenticatorData();
@@ -123,14 +116,12 @@ if ($userVerified) {
$flags = $authenticatorData->getFlags();
$uvFlag = ($flags & 0x04) !== 0; // UV flag is bit 2
```
-{% endcode %}
-## Practical Examples
+## Practical examples
-### Example 1: High-Security Banking App
+### Example 1: High-security banking app
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Require user verification for all operations
$authenticatorSelection = AuthenticatorSelectionCriteria::create(
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED
@@ -144,12 +135,10 @@ $options = PublicKeyCredentialCreationOptions::create(
authenticatorSelection: $authenticatorSelection
);
```
-{% endcode %}
-### Example 2: General Web Application
+### Example 2: General web application
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Prefer user verification but don't require it
$authenticatorSelection = AuthenticatorSelectionCriteria::create(
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED
@@ -163,21 +152,18 @@ $options = PublicKeyCredentialCreationOptions::create(
authenticatorSelection: $authenticatorSelection
);
```
-{% endcode %}
-### Example 3: Fast Re-authentication
+### Example 3: Fast re-authentication
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// For quick re-auth on already logged-in user, discourage UV
$options = PublicKeyCredentialRequestOptions::create(
challenge: random_bytes(32),
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_DISCOURAGED
);
```
-{% endcode %}
-## Device Capabilities
+## Device capabilities
Different authenticators have different user verification capabilities:
@@ -190,28 +176,27 @@ Different authenticators have different user verification capabilities:
| **YubiKey Bio** | Fingerprint |
| **Basic security keys** | None (only user presence) |
-{% hint style="info" %}
-When you set `userVerification: required`, only authenticators capable of user verification will be available to the user during registration or authentication.
-{% endhint %}
+!!! info
-## Best Practices
+ When you set `userVerification: required`, only authenticators capable of user verification will be available to the user during registration or authentication.
-### For Registration
+## Best practices
+
+### For registration
1. **Use `preferred` as default** - Balances security and compatibility
2. **Use `required` for sensitive accounts** - Banking, healthcare, admin accounts
3. **Inform users** - Explain that biometric/PIN improves security
-### For Authentication
+### For authentication
1. **Match registration settings** - If registered with `required`, authenticate with `required`
2. **Allow `preferred` for convenience** - Users can choose faster auth if device supports it
3. **Document your policy** - Make clear what level of verification is expected
-### Conditional Logic
+### Conditional logic
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
// Require UV only for privileged operations
$isAdminAction = ($user->getRole() === 'ROLE_ADMIN');
@@ -224,9 +209,8 @@ $options = PublicKeyCredentialRequestOptions::create(
userVerification: $userVerification
);
```
-{% endcode %}
-## Common Issues
+## Common issues
### Issue: "User verification not supported"
@@ -240,19 +224,18 @@ $options = PublicKeyCredentialRequestOptions::create(
**Solution**: Use `discouraged` or `preferred` for routine operations, save `required` for sensitive actions.
-## Security Considerations
+## Security considerations
* ✅ **Higher assurance** - UV provides stronger identity verification than UP alone
* ✅ **Phishing resistant** - Even if an attacker steals the authenticator, they need the PIN/biometric
* ⚠️ **Not foolproof** - Biometric systems can have false positives; PINs can be observed
* ⚠️ **Device dependent** - Relying solely on UV limits compatible devices
-## Constants Reference
+## Constants reference
The library provides convenient constants in the `AuthenticatorSelectionCriteria` class:
-{% code lineNumbers="true" %}
-```php
+```php linenums="1"
use Webauthn\AuthenticatorSelectionCriteria;
// For registration (attestation)
@@ -263,9 +246,8 @@ AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_DISCOURAGED
// These same constants can be used for authentication (assertion)
// in PublicKeyCredentialRequestOptions
```
-{% endcode %}
-## See Also
+## See also
* [Authenticators](authenticators.md) - Learn about different authenticator types
* [Authenticator Selection Criteria](../pure-php/advanced-behaviours/authenticator-selection-criteria.md) - Detailed configuration
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..a118efe
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,234 @@
+site_name: WebAuthn Framework
+site_description: WebAuthn and passkeys for PHP and Symfony. Registration and authentication ceremonies, the Symfony bundle and the Symfony UX components, after WebAuthn Level 3.
+site_url: https://webauthn-doc.spomky-labs.com/
+site_author: Spomky-Labs
+repo_url: https://github.com/web-auth/webauthn-framework
+repo_name: web-auth/webauthn-framework
+edit_uri: https://github.com/web-auth/doc/edit/5.2/docs/
+
+docs_dir: docs
+site_dir: site
+
+# The GitBook table of contents. It stays while GitBook serves the domain, and the navigation below says the
+# same thing in the words of MkDocs.
+exclude_docs: |
+ SUMMARY.md
+
+theme:
+ name: material
+ custom_dir: docs/overrides
+ language: en
+ # Space Grotesk and IBM Plex Mono are served from assets/fonts, declared in slabs.css: the theme loads
+ # no font of its own.
+ font: false
+ icon:
+ repo: fontawesome/brands/github
+ edit: material/pencil-outline
+ annotation: material/plus-circle
+ favicon: assets/brand/favicon.svg
+ palette:
+ - media: "(prefers-color-scheme)"
+ toggle:
+ icon: material/brightness-auto
+ name: Follow the system theme
+ - media: "(prefers-color-scheme: light)"
+ scheme: default
+ primary: custom
+ accent: custom
+ toggle:
+ icon: material/weather-sunny
+ name: Switch to the dark theme
+ - media: "(prefers-color-scheme: dark)"
+ scheme: slate
+ primary: custom
+ accent: custom
+ toggle:
+ icon: material/weather-night
+ name: Switch to the light theme
+ features:
+ - navigation.instant
+ - navigation.instant.progress
+ - navigation.tracking
+ - navigation.sections
+ - navigation.indexes
+ - navigation.top
+ - navigation.footer
+ - toc.follow
+ - search.suggest
+ - search.highlight
+ - search.share
+ - content.code.copy
+ - content.code.annotate
+ - content.tabs.link
+ - content.tooltips
+ - content.action.edit
+
+# The tokens of the Slabs design kit, as they are, then the rules that apply them.
+extra_css:
+ - assets/stylesheets/slabs-tokens.css
+ - assets/stylesheets/slabs.css
+
+plugins:
+ - search
+ # Every asset is served from this site. Should a page ever reference an external one, it is downloaded
+ # at build time: nothing a reader loads reaches a third party.
+ - privacy
+ - git-revision-date-localized:
+ enable_creation_date: false
+ type: date
+ fallback_to_build_date: true
+ - redirects:
+ redirect_maps: {}
+
+markdown_extensions:
+ - abbr
+ - admonition
+ - attr_list
+ - def_list
+ - footnotes
+ - md_in_html
+ - tables
+ - toc:
+ title: On this page
+ permalink: true
+ permalink_title: Link to this section
+ toc_depth: 3
+ - pymdownx.betterem
+ - pymdownx.caret
+ - pymdownx.details
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+ - pymdownx.highlight:
+ anchor_linenums: true
+ # A PHP block of these pages starts without "
+
+
+
+
+
+ Page not found · WebAuthn Framework
+
+
+
+
+
+
+
+
+
Looking for this page in the latest version…
+
+
+
Page not found
+
This page has moved or never existed. Search, or start from one of these: