Cross origin authentication¶
Default behavior¶
By default, the current host is used, and the origin parameter returned in the WebAuthn authenticator response must be identical. Additionally, only the HTTPS scheme is allowed. This may cause issues in several situations, such as:
- Using multiple origins: If your application is accessible from multiple domains (e.g.,
example.comandapp.example.com), the default behavior will reject authentication attempts from different origins. - Supporting native applications: Companion applications on mobile or desktop may use different schemes (e.g.,
android:apk-key-hash://orios:bundle-id://), which are not covered by the default host-based validation. - 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¶
To handle these cases, you can explicitly define a list of allowed origins when configuring the WebAuthn authentication process using the method setAllowedOrigins.
Info
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.
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAllowedOrigins([
'https://acme.com',
'https://acme.fr',
'https://acme.de',
'https://old-acme.com'
]);
Allowing subdomains¶
To allow authentication from subdomains dynamically, enable the allowSubdomains flag:
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAllowedOrigins(['https://acme.com'], true);
With this setting, authentication requests from https://sub.acme.com will be considered valid.
Danger
Do not use TLD and the sub domain flag together! $csmFactory->setSecuredRelyingPartyId(['com'], true);
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:
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAllowedOrigins([
'https://acme.com',
'android:apk-key-hash://your-app-hash',
'ios:bundle-id://your.bundle.id',
]);
This configuration allows authentication responses from web browsers and native applications.
Info
Changed in v5.3.3: an entry that is not a URL, i.e. that has a scheme but no host, such as android:apk-key-hash:<base64>, is stored as is and compared verbatim with the origin field of the client data. Entries made of a host only, such as acme.com, are still normalized to https://acme.com because WebAuthn requires TLS.
Copy the facet identifier exactly as the application sends it. Before v5.3.3 these entries went through the host normalization and were turned into unusable origins such as https://android:apk-key-hash:..., so they never matched.
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:
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAllowedOrigins([
'http://localhost',
]);
Be aware that this should only be enabled in non-production environments.
Top origin validation (cross-origin iframes)¶
When the ceremony takes place in a cross-origin iframe, for example a page of auth.example.com embedded in app.example.com, the browser sets crossOrigin to true in the client data and adds the origin of the embedding page in a topOrigin field.
Danger
Changed in v5.3.4: a response that carries a topOrigin is rejected unless a TopOriginValidator is configured. Previous versions accepted such a response without checking anything, which means any site embedding your ceremony in an iframe was accepted.
Applications that do not use iframes have nothing to do: a same-origin ceremony has no topOrigin at all. Applications that are legitimately embedded must opt in with one of the validators below, otherwise their ceremonies now fail.
The step also rejects a response whose client data carries a topOrigin while crossOrigin is false, as the two fields contradict each other.
Using the built-in host validator¶
HostTopOriginValidator compares the received top origin with a fixed value:
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
use Webauthn\CeremonyStep\HostTopOriginValidator;
$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->enableTopOriginValidator(
new HostTopOriginValidator('https://app.example.com')
);
Warning
The comparison is strict. The expected value is the top origin as the browser sends it, i.e. a serialized origin such as https://app.example.com, and not a bare host name.
Using a custom validator¶
When several parent origins are allowed, implement the TopOriginValidator interface:
<?php
declare(strict_types=1);
use Webauthn\CeremonyStep\TopOriginValidator;
use Webauthn\Exception\AuthenticatorResponseVerificationException;
final readonly class AllowedTopOriginsValidator implements TopOriginValidator
{
/**
* @param string[] $allowedTopOrigins
*/
public function __construct(
private array $allowedTopOrigins
) {
}
public function validate(string $topOrigin): void
{
if (!in_array($topOrigin, $this->allowedTopOrigins, true)) {
throw AuthenticatorResponseVerificationException::create(
'The top origin is not allowed.'
);
}
}
}
Then register it:
$csmFactory->enableTopOriginValidator(
new AllowedTopOriginsValidator([
'https://app.example.com',
'https://dashboard.example.com',
])
);
A validator set on the factory applies to both the creation and the request ceremonies. disableTopOriginValidator() removes it, which is useful when the same factory is reused to build a manager for a context where iframes are not allowed.
Security considerations¶
When modifying allowed origins, ensure that:
- You only allow trusted origins to prevent phishing attacks.
- You enforce HTTPS wherever possible. Some browsers support
https://localhost, so prefer it overhttp://localhostwhen feasible. - You keep the list of allowed top origins as small as possible. Any site listed there is allowed to embed your ceremony.
By properly configuring allowed origins, you can support a variety of WebAuthn use cases while maintaining security best practices.