# 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.com` and `app.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://` or `ios: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`.

{% hint style="info" %}
The method `setSecuredRelyingPartyId` is deprecated since 5.2.0
{% endhint %}

### 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

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'
]);
```

{% endcode %}

### Allowing Subdomains

To allow authentication from subdomains dynamically, enable the `allowSubdomains` flag:

{% code lineNumbers="true" %}

```php
<?php

declare(strict_types=1);

use Webauthn\CeremonyStep\CeremonyStepManagerFactory;

$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->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 %}

### 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

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',
]);
```

{% endcode %}

This configuration allows authentication responses from web browsers and native applications.

### 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

declare(strict_types=1);

use Webauthn\CeremonyStep\CeremonyStepManagerFactory;

$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->setAllowedOrigins([
    'http://localhost.com',
]);
```

{% endcode %}

Be aware that this should only be enabled in non-production environments.

## 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

The `HostTopOriginValidator` performs a strict comparison between the top origin and a given host:

{% code lineNumbers="true" %}

```php
<?php

declare(strict_types=1);

use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
use Webauthn\CeremonyStep\HostTopOriginValidator;

$csmFactory = new CeremonyStepManagerFactory();
$csmFactory->enableTopOriginValidator(
    new HostTopOriginValidator('app.example.com')
);
```

{% endcode %}

### Using a Custom Validator

For more advanced scenarios (e.g., allowing multiple top origins), implement the `TopOriginValidator` interface:

{% code lineNumbers="true" %}

```php
<?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.'
            );
        }
    }
}
```

{% endcode %}

Then register it:

{% code lineNumbers="true" %}

```php
$csmFactory->enableTopOriginValidator(
    new AllowedTopOriginsValidator([
        'https://app.example.com',
        'https://dashboard.example.com',
    ])
);
```

{% 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 %}

## 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 over `http://localhost` when feasible.

By properly configuring allowed origins, you can support a variety of WebAuthn use cases while maintaining security best practices.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://webauthn-doc.spomky-labs.com/v5.2/pure-php/advanced-behaviours/dealing-with-localhost.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
