If you have troubles during the development of your application or if you want to keep track of every critical/error messages in production, you can use a PSR-3 compatible logger.
Several classes implement the interface Webauthn\MetadataService\CanLogData. This interface allows setting a PSR-3 logger instance.
User Verification
You can indicate the user verification requirements during the ceremonies by setting the value in your options.
Authenticator registration
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
$publicKeyCredentialCreationOptions =
PublicKeyCredentialCreationOptions::create(
$rpEntity,
$userEntity,
$challenge,
authenticatorSelection: AuthenticatorSelectionCriteria::create(AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_DISCOURAGED)
)
;
User Authentication
// Public Key Credential Request Options
use Webauthn\PublicKeyCredentialRequestOptions;
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
random_bytes(32),
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DISCOURAGED
);
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.
The Webauthn API and this library allow you to define a set of options to disallow the registration of authenticators that do not fulfill with the conditions.
The class Webauthn\AuthenticatorSelectionCriteria is designed for this purpose. It is used when generating the Webauthn\PublicKeyCredentialCreationOptions object.
Available Criteria
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).
Possible values are:
AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_NO_PREFERENCE: there is no requirement (default value),
AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_PLATFORM: the authenticator must be attached,
AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM: must be a roaming authenticator.
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
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.
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.
// Public Key Credential Request Options
use Webauthn\PublicKeyCredentialRequestOptions;
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
random_bytes(32),
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED
);
The default values for the user verification and the resident key are set to preferred and resident keys may be created if the authenticator is compatible. This means that some users may log in without username.
Authenticator Algorithms
The Webauthn data verification is based on cryptographic signatures and thus you need to provide cryptographic algorithms to perform those checks.
The following algorithms are required in most situations:
<?php
declare(strict_types=1);
use Cose\Algorithm\Manager;
use Cose\Algorithm\Signature\ECDSA\ES256;
use Cose\Algorithm\Signature\RSA\RS256;
$algorithmManager = Manager::create()
->add(
ES256::create(),
RS256::create()
)
;
The order is important. By adding ES256 first, the relyaing party prefers an ES256 credential. Browsers are eager to satisfy preferences.
The complete list of supported algorithms:
<?php
declare(strict_types=1);
use Cose\Algorithm\Manager;
use Cose\Algorithm\Signature\ECDSA\ES256;
use Cose\Algorithm\Signature\ECDSA\ES256K;
use Cose\Algorithm\Signature\ECDSA\ES384;
use Cose\Algorithm\Signature\ECDSA\ES512;
use Cose\Algorithm\Signature\EdDSA\Ed256;
use Cose\Algorithm\Signature\EdDSA\Ed512;
use Cose\Algorithm\Signature\RSA\PS256;
use Cose\Algorithm\Signature\RSA\PS384;
use Cose\Algorithm\Signature\RSA\PS512;
use Cose\Algorithm\Signature\RSA\RS256;
use Cose\Algorithm\Signature\RSA\RS384;
use Cose\Algorithm\Signature\RSA\RS512;
$algorithmManager = Manager::create()
->add(
ES256::create(),
ES256K::create(),
ES384::create(),
ES512::create(),
RS256::create(),
RS384::create(),
RS512::create(),
PS256::create(),
PS384::create(),
PS512::create(),
Ed256::create(),
Ed512::create(),
)
;
The algorithm manager can be injected to your Ceremony Step Manager Factory.
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAlgorithmManager($algorithmManager);
Attestation and Metadata Statement
Important Notice: The request for an Attestation Statement is reserved for applications necessitating a high degree of reliability, such as those operated by banking or financial institutions, government agencies, etc. Exercise caution and ensure your application's context requires such a level of trust before proceeding.
Attestation Statement Support Manager
There are few steps to acheive. First, you have to add support classes for all attestation statement types into your Attestation Metatdata Manager.
For 4.5.0, the TPMAttestationStatementSupport class accepts a PSR-20 clock as argument. This argument will be mandatory for 5.0.0.
In the example below, we use symfony/clock component.
<?php
declare(strict_types=1);
use Cose\Algorithm\Manager;
use Cose\Algorithm\Signature\ECDSA;
use Cose\Algorithm\Signature\RSA;
use Webauthn\AttestationStatement\AndroidKeyAttestationStatementSupport;
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
use Webauthn\AttestationStatement\FidoU2FAttestationStatementSupport;
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
use Webauthn\AttestationStatement\PackedAttestationStatementSupport;
use Webauthn\AttestationStatement\TPMAttestationStatementSupport;
use Webauthn\AttestationStatement\AppleAttestationStatementSupport;
use Symfony\Component\Clock\NativeClock;
//We need a PSR-20 clock
$clock = new NativeClock();
// You normally already do this
$attestationStatementSupportManager = AttestationStatementSupportManager::create();
$attestationStatementSupportManager->add(NoneAttestationStatementSupport::create());
// Additional classes to add
$attestationStatementSupportManager->add(FidoU2FAttestationStatementSupport::create());
$attestationStatementSupportManager->add(AppleAttestationStatementSupport::create());
$attestationStatementSupportManager->add(AndroidKeyAttestationStatementSupport::create());
$attestationStatementSupportManager->add(TPMAttestationStatementSupport::create($clock));
// Cose Algorithm Manager
// The list of algorithm depends on the algorithm list you defined in your options
// You should use at least ES256 and RS256 algorithms that are widely used.
$coseAlgorithmManager = Manager::create();
$coseAlgorithmManager->add(ECDSA\ES256::create());
$coseAlgorithmManager->add(RSA\RS256::create());
$attestationStatementSupportManager->add(PackedAttestationStatementSupport::create($coseAlgorithmManager));
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).
Your Metadata Statement Repository must implement the interface Webauthn\MetadataService\MetadataStatementRepository that has only one method:
findOneByAAGUID(string $aaguid): this method retrieves the MetadataStatement object with AAGUID. It shall return null in case of the absence of the MDS.
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
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:
findStatusReportsByAAGUID(string $aaguid): this method returns a list of Status Reports for the given AAGUID.
The verification's success or failure depends on the state reported in the most recent Status Report.
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) and a PSR-20 Clock.
<?php
use Webauthn\MetadataService\CertificateChain\PhpCertificateChainValidator;
$certificateChainValidator = PhpCertificateChainValidator::create(
$httpClient,
$clock
);
Ceremony Step Manager Factory
The services described above must be set to the Ceremony Step Manager Factory. The CSM you will create will verifiy the attestation statement sent by the authenticator.
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAttestationStatementSupportManager($attestationStatementSupportManager);
$csmFactory->enableMetadataStatementSupport(
$metadataStatementRepository,
$statusReportRepository,
$certificateChainValidator,
);
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.
There are 3 conveyance modes available using PHP constants provided by the class Webauthn\PublicKeyCredentialCreationOptions:
ATTESTATION_CONVEYANCE_PREFERENCE_NONE: the Relying Party is not interested in authenticator attestation (default)
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.
The following example is totally fictive. We will add an extension input loc=true to the request option object.
<?php
declare(strict_types=1);
use Webauthn\AuthenticationExtensions\AuthenticationExtension;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\PublicKeyCredentialRequestOptions;
// Extensions
$extensions = AuthenticationExtensions::create([
AuthenticationExtension::create('loc', true)
]);
// Public Key Credential Request Options
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
random_bytes(32), // Challenge
extensions: $extensions
);
Extension Output Checker
An Extension Output Checker (EOC) will check the extension output.
It must implement the interface Webauthn\AuthenticationExtensions\ExtensionOutputChecker and throw an exception of type Webauthn\AuthenticationExtension\ExtensionOutputError in case of error.
Devices may ignore the extension inputs. The extension outputs are therefore not guaranteed.
In the previous example, we asked for the location of the device and we expect to receive geolocation data in the extension output.
<?php
declare(strict_types=1);
namespace Acme\Extension;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\AuthenticationExtensions\ExtensionOutputChecker;
use Webauthn\AuthenticationExtensions\ExtensionOutputError;
final class LocationExtensionOutputChecker implements ExtensionOutputChecker
{
public function check(AuthenticationExtensions $inputs, AuthenticationExtensions $outputs): void
{
if (!$inputs->has('loc') || $inputs->get('loc') !== true) {
return;
}
if (!$outputs->has('loc')) {
//You may simply return but here we consider it is a mandatory extension output.
throw new ExtensionOutputError(
$inputs->get('loc'),
'The location of the device is missing'
);
}
$location = $outputs->get('loc');
//... Proceed with the output e.g. by logging the location of the device
// or verifying it is in a specific area.
}
}
Extension Output Checker Handler
You can create as many EOC as needed. These services can be managed by a handler that will be injected to the Ceremony Step Manager Factory. Extensions will be automatically verified during the validation steps.
<?php
declare(strict_types=1);
namespace Acme\Extension;
use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler;
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$eocHandler = ExtensionOutputCheckerHandler::create();
$eocHandler->add(new LocationExtensionOutputChecker());
// Add more EOC if needed.
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setExtensionOutputCheckerHandler($eocHandler);
Authenticator Counter
The authenticators may have an internal counter. This feature is very helpful to detect cloned devices.
The default behaviour is to reject the assertions. This behaviour might cause some troubles as it could reject the real device whilst the fake one can continue to be used.
It is therefore required to go deeper in the protection of your application by logging the error and locking the associated account.
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.
<?php
declare(strict_types=1);
namespace App\Service;
use App\SecuritySystem;
use Throwable;
use Webauthn\Counter\CounterChecker;
use Webauthn\PublicKeyCredentialSource;
final class CustomCounterChecker implements CounterChecker
{
private $securitySystem;
public function __construct(SecuritySystem $securitySystem)
{
$this->securitySystem = $securitySystem ;
}
public function check(PublicKeyCredentialSource $publicKeyCredentialSource, int $currentCounter): void
{
try {
assert($currentCounter > $publicKeyCredentialSource->counter, 'Invalid counter.');
} catch (Throwable $throwable) {
$this->securitySystem->fakeDeviceDetected($publicKeyCredentialSource);
throw $throwable;
}
}
}
The Counter Checker service can be injected to your Ceremony Step Manager Factory.
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setCounterChecker($customCounterChecker);
Dealing with “localhost”
Secured Context
If your are working on a development environment, https may not be available but the context could be considered as secured. You can bypass the scheme verification by passing the list of rpIds you consider secured.
Please be careful using this feature. It should NOT be used in production.
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setSecuredRelyingPartyId(['secure.localhost']);