| Browser | Cross-origin login ( navigator.credentials.get) | Cross-origin creation ( navigator.credentials.create) |
|---|---|---|
| Chrome/Edge | ✅ Chrome 84 (July 2020) | ✅ Chrome 123 (March 2024) |
| Firefox | ✅ Firefox 118 (Sept 2023) | ✅ Firefox 123 (Feb 2024) |
| Safari | ✅ Safari 15.5 (May 2022) | ❌ Not supported |
Legend
✅ = supported ❌ = not supported
Safari note: WebKit shipped cross-origin navigator.credentials.get() support in Safari
15.5, but Safari still does not support cross-origin navigator.credentials.create() and
does not expose topOrigin in clientDataJSON as of May 2026. Test the exact browser and
platform combinations that matter for your flow, especially if you rely on iframe
Permissions Policy feature tokens.
Week after week, more and more organizations announce their passkey rollouts (e.g. lately Visa, Mastercard or Vercel). As developers and product managers from other companies follow these role models, more use cases of passkey implementation are discussed.

Buy vs. Build Guide. Practical guidance, rollout patterns, and KPIs for passkey programs.
One case we are constantly asked for is how passkeys work in iframes, as iframes are widely used in modern web development to embed content from different sources seamlessly. In the context of passkeys and WebAuthn, iframes come with their own set of challenges, especially concerning security and user interactions.
Integrate passkeys as Payment Provider via 3rd party SDK.
This blog post provides a comprehensive guide on using passkeys and WebAuthn in iframes. We will
By the end of this post, you will have a clear understanding of how to leverage passkeys within iframes.
iframes, or inline frames, are HTML elements that allow developers to embed another HTML document within the current document. This capability is widely used to incorporate content from external sources, such as videos, maps, and other web pages, into a website.
Let’s have a look at the different types of iframes.
Subscribe to our Passkeys Substack for the latest news.
The basic iframe is the most commonly used type. It simply embeds content from another URL within the current page.
<iframe src="https://example.com"></iframe>
This basic iframe is often used to include static content, like an article, within a web page.
Responsive iframes are designed to adjust their size based on the screen size or the container they are placed in. This ensures that the embedded content looks good on all devices, including desktops, tablets, and mobile phones.
<iframe src="https://example.com" style="width: 100%; height: 500px;"></iframe>
CSS media queries can also be used to make the iframe adjust dynamically based on the viewport size.
Get a free passkey assessment in 15 minutes.
A secure or sandboxed iframe restricts the actions that can be performed within the iframe. This is useful for embedding content from untrusted sources or for enhancing security.
<iframe src="https://example.com" sandbox></iframe>
The sandbox attribute can include various restrictions, such as:
<iframe src="https://example.com" sandbox="allow-scripts allow-same-origin"></iframe>
The sandbox attribute allows scripts to run but restricts potentially dangerous actions, like form submissions or plugin usage.
Become part of our Passkeys Community for updates & support.
Cross-origin iframes embed content from a different domain. They are commonly used for integrating third-party services, such as payment gateways or social media widgets. Due to security restrictions, these iframes have limited access to the embedding page's content and vice versa.
Cross-origin means that the content being loaded is from a different origin, where an
origin is defined by the combination of the scheme (protocol), host (domain), and port
number. For example, https://example.com and http://example.com are considered
different origins because they use different schemes (HTTP vs. HTTPS).
Similarly, subdomains are treated as separate origins from their parent domains. For
instance, https://example.com and https://sub.example.com are cross-origin, even
though they share the same base domain. This separation ensures that scripts and data from
one subdomain cannot directly interact with those from another without explicit
permission, enhancing security.
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
See how VicRoads scaled passkeys to 5M+ users — alongside their existing IDP.
Read the case studyHere are examples to illustrate the concepts of cross-origin and same-origin:
Cross-origin example:
Embedding content from https://payment.example.com into a webpage hosted on https://www.mystore.com. These are cross-origin because they have different domains.
Same-origin example:
Embedding content from https://www.example.com/shop into a webpage hosted on https://www.example.com/blog. These are same-origin because they share the same scheme, host, and port.
Cross-origin iframes differ from same-origin iframes in that the iframe source has a
different scheme, host or port than the embedding page, whereas a same-origin iframe
shares the exact same scheme, host and port as the page that embeds it. Note that
same-origin is
stricter than same-site: two
URLs can be same-site (same registrable domain, e.g. support.example.com and
developer.example.com) but still cross-origin because their hosts differ. Browsers
enforce WebAuthn iframe rules based on origin, not site.
<iframe src="https://anotherdomain.com"></iframe>
Using passkeys in iframes introduces new capabilities and constraints that developers need to understand, primarily revolving around setting the correct permissions and ensuring secure user interactions within the embedded context.
Historically, the Web Authentication API was disabled by default in cross-origin iframes, primarily due to security concerns. This limitation meant developers had to redirect users or use pop-up windows for authentication, leading to a less seamless user experience.
In passkeys / WebAuthn, there are two core operations (also called ceremonies):
The two operations were and are not supported equally in cross-origin iframes:
At first, the login via cross-origin iframes was made possible but cross-origin creation not yet because there wasn't anyone with a use case.
Recent advancements in Chrome / Edge 123 and Firefox 123 have introduced support for the creation of cross-origin iframe passkeys under specific conditions. However, as of May 2026, not all browsers fully support the creation of passkeys via cross-origin iframes: Safari supports cross-origin passkey login but still does not support cross-origin passkey creation.
Moreover, cross-origin iframe support (for register and authentication operations) is already incorporated into the ongoing WebAuthn Level 3 specification. Some browsers still need to catch up to the specification (e.g. Safari). Unfortunately, Apple has not yet announced if and when it will allow for cross-origin registration of passkeys within Safari. This would lift the most significant technical limitation for using passkeys in cross-origin iframes.
In the following parts of the blog post, we assume the use of cross-origin iframes.
See how many people actually use passkeys.
The following tables provide an overview of browser/standard support for iframe authentication and iframe login via passkeys in cross-origin iframe contexts:
| Browser/Standard | First-Party-Context | Third-Party-Context |
|---|---|---|
| Required in WebAuthn Level 2 | ✔️ | ✔️ |
| Required in WebAuthn Level 3 | ✔️ | ✔️ |
| Implemented in Chrome | ✔️ | ✔️ |
| Implemented in Firefox | ✔️ | ✔️ |
| Implemented in Safari | ✔️ | ✔️ |
As of May 2026, the creation of a passkey in a cross-origin iframe is not yet possible in all browsers. The following table provides an overview of the browser / standard support for the registering / creation of passkeys in cross-origin iframes:
| Browser/Standard | First-Party-Context | Third-Party-Context |
|---|---|---|
| Required in WebAuthn Level 2 | ✔️ Details | ❌ |
| Required in WebAuthn Level 3 | ✔️ Details | ✔️ Details |
| Implemented in Chrome | ✔️ Details | ✔️ Details |
| Implemented in Firefox | ✔️ Details | ✔️ Details |
| Implemented in Safari | ✔️ Details | Awaiting signal for implementation |
If you’re interested in more background to this development and support, we recommend having a look at this GitHub issue and this Pull Request.
The reason browsers block WebAuthn in cross-origin iframes by default is not just historical caution. A passkey prompt can be triggered from a hidden or visually disguised frame if the browser and server do not enforce the embedding context. Two threat models are especially important:
The right model is defense in depth, combining browser-enforced requirements with recommended hardening.
Required for cross-origin iframe passkeys to work at all:
Permissions-Policy and the iframe allow attribute. Without this, browsers block
navigator.credentials.get() and navigator.credentials.create() entirely in the
iframe.Strongly recommended hardening for iframe-specific threats:
frame-ancestors to prevent unauthorized embedding and clickjacking.clientDataJSON: crossOrigin === true for intended iframe flows, and topOrigin
against an allowlist where the browser provides it.postMessage() flow. If you use postMessage() at all, never pass "*" as the target
origin and always check event.origin on the receiving side.Together, these controls turn cross-origin iframe support from "the API is enabled" into "the API is enabled only for the intended parent, user action and server-side ceremony."
There are two major use cases for supporting passkeys in cross-origin iframes.
Enabling passkeys in cross-origin iframes is crucial for federated identity scenarios where multiple domains are involved but the same user accounts should be used.
Let’s take the following scenario. You’re a multinational company like KAYAK and have different domains for different regions:
However, you have one central identity management system that enables users to log in with the same account and credentials on all these domains. The WebAuthn standard would pose a challenge to these scenarios, as the passkeys can be bound to only one domain (Relying Party ID), e.g. www.kayak.com.
To overcome this challenge, you would use an iframe from the origin www.kayak.com on all your other domains. So you embed an iframe with www.kayak.com origin on www.kayak.us and on www.kayak.de (cross-origin iframe). Otherwise, the usage of your “www.kayak.com”-bound passkeys on these other domains would not be possible due to the phishing-resistance of passkeys.
On a site note: Also the new WebAuthn feature of Related Origin Requests (RoR) could be used alternatively. This feature allows “related origins” to access passkeys without iframes and is now supported across all major browsers (Chrome/Edge 128+, Safari 18+ and Firefox 152+).
Also for seamless payment flows, the usage of passkeys in cross-origin iframes plays an important role. Consider the following scenario: A customer wants to buy new shoes on a merchant’s website (e.g. www.amazon.com). This merchant’s website allows the customer to pay via the bank account (e.g. at www.revolut.com) and thus requires the user to log into the bank’s website (this is a simplified process). The user logs in to the bank’s website with a passkey that is bound to the bank’s Relying Party ID, e.g. “revolut.com”.
Integrate passkeys as Payment Provider via 3rd party SDK.
To avoid redirecting the user from the merchant’s website (www.amazon.com) to the bank’s website (www.revolut.com) in the checkout process and let the user log in there to the bank’s account, a cross-origin iframe can be used. Hereby, the user stays on www.amazon.com and uses the passkey in the cross-origin iframe for authentication that they created for www.revolut.com.
Thus, integrating passkeys via cross-origin iframes in payment flows ensures secure and streamlined transactions across consumers, merchants and banks:
| Consumers | Merchants | Banks |
|---|---|---|
|
|
|
In the context of payment and passkeys, we also recommend taking a look at our blog post on Secure Payment Confirmation (SPC) and dynamic linking with passkeys. Be sure to also take a look at the limitations for third-party-context in Native Apps below.
Additionally, for a more in-depth view of cross-origin payment flows using passkeys, see our Payment Provider Passkeys: How to Build a 3rd Party SDK.
In general, integrating passkeys within iframes offers several benefits, mainly by improving the UX and security. Here’s a breakdown of these advantages:
Enhanced User Experience
Improved Security
Implementing passkeys in iframes involves some key steps to ensure security and functionality. We provide a detailed guide for developers. Please see also the example implementation at https://cross-origin-iframe.vercel.app/.
Browsers block WebAuthn in cross-origin iframes by default. To enable it safely, the
top-level page must delegate the feature to the trusted iframe origin with
Permissions-Policy, and the iframe markup must opt into the same feature tokens.
Use the parent page's HTTP response header to allow the embedded origin:
Permissions-Policy: publickey-credentials-get=(self "https://passkeys.eu"), publickey-credentials-create=(self "https://passkeys.eu")
Then add the matching allow attribute to the iframe:
<iframe src="https://passkeys.eu" allow="publickey-credentials-get; publickey-credentials-create" ></iframe>
If your iframe only performs login, delegate only publickey-credentials-get. If it also
creates passkeys, delegate publickey-credentials-create. Avoid broad wildcard policies
in production unless every possible embedded origin is truly trusted.
The HTTP Permissions Policy was previously called Feature Policy. The modern
Permissions-Policy header uses comma-separated directives, while the iframe allow
attribute uses semicolon-separated directives. Also note that a meta tag using
http-equiv="Permissions-Policy" is not a reliable substitute for the HTTP response
header; configure this on the parent server response.
Permissions-Policy answers whether the iframe can call WebAuthn. It does not answer who
is allowed to frame the authentication endpoint. The embedded authentication origin should
restrict allowed parent pages with CSP frame-ancestors:
Content-Security-Policy: frame-ancestors 'self' https://merchant.example https://checkout.example;
The parent page should also restrict which frames it can load, for example:
Content-Security-Policy: frame-src https://passkeys.eu;
X-Frame-Options is still useful for routes that should never be embedded, but it cannot
express a partner-origin allowlist. For embeddable authentication routes, prefer
frame-ancestors and keep the allowlist narrow. You can add an
Intersection Observer
check as an additional clickjacking signal, but it should not replace server-side and CSP
controls.
Cross-origin iframe authentication often needs a short-lived session inside the embedded origin. Modern browsers increasingly restrict third-party cookies, so configure any necessary iframe session cookies explicitly:
Set-Cookie: iframe_session=...; Path=/; HttpOnly; SameSite=None; Secure; Partitioned
SameSite=None allows the cookie to be sent in a
third-party iframe context, Secure
is required by modern browsers for such cookies, and Partitioned opts into CHIPS so the
cookie is scoped per top-level site. In some browsers and privacy modes, you may also need
to use the
Storage Access API
or fall back to a redirect-based flow.
Ensure that the iframe content requires a user action to trigger passkey authentication. This can be done using event listeners for clicks or form submissions within the iframe. This process is also called transient activation.
document.getElementById("loginPasskeyButton").addEventListener("click", async () => { try { const publicKeyCredentialRequestOptions = { /* Configuration options */ }; const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, }); // Send the assertion to your server for verification. } catch (err) { console.error("Error authenticating via passkey:", err); } });
In this context, see also our blog post on Safari user gesture requirements.
clientDataJSON Server-Side#The browser-side permission check is not enough. The
Relying Party server must still verify the WebAuthn response
and confirm that the ceremony came from the expected iframe context. In addition to the
standard challenge, origin, user presence and
signature checks, inspect the decoded clientDataJSON:
const clientData = JSON.parse( Buffer.from(assertion.response.clientDataJSON).toString("utf8"), ); if (expectedIframeFlow && clientData.crossOrigin !== true) { throw new Error("Expected a cross-origin iframe WebAuthn ceremony"); } if ( expectedIframeFlow && typeof clientData.topOrigin === "string" && !allowedTopOrigins.has(clientData.topOrigin) ) { throw new Error("Unexpected top-level origin for iframe WebAuthn ceremony"); }
crossOrigin indicates that the API was invoked in a cross-origin iframe. topOrigin
identifies the top-level browsing context that was visible in the browser address bar. For
iframe-based passkey flows, validate topOrigin against your allowlist where the browser
provides it.
Safari does not expose topOrigin as of May 2026. If your risk model requires this
server-side signal, use a redirect fallback for Safari. If you support Safari iframe
login, compensate with a tight frame-ancestors allowlist, nonce-bound session
establishment and partner-specific server checks.
postMessage()#After the iframe completes WebAuthn with its own server, it typically hands a result back
to the parent page. The standard browser primitive for this is postMessage(). The
iframe-passkey-specific guidance is:
window.parent.postMessage(payload, parentOrigin)
"*" as the target origin.event.origin === providerOrigin) and forward the token to your backend.The receiving check on the parent is the most error-prone step:
window.addEventListener("message", async (event) => { if (event.origin !== "https://passkeys.eu") return; if (event.data?.type !== "passkey-authenticated") return; await fetch("/api/passkey-iframe-session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: event.data.token, expectedNonce: "deadbeef12345678", }), }); });
In the following, you find a compact index.html example for a parent page that embeds a
cross-origin passkey iframe via https://passkeys.eu. In production,
the HTTP headers shown above must be sent by the server; do not rely on <meta> tags for
Permissions-Policy.
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Cross-Origin iframe with Passkeys Demo</title> </head> <body> <h1>Cross-Origin iframe with Passkeys Demo</h1> <iframe src="https://passkeys.eu" allow="publickey-credentials-get; publickey-credentials-create" width="800" height="600" ></iframe> </body> </html>
Implementing passkeys in iframes can come with a set of challenges that developers need to address to ensure a smooth and secure user experience. Here’s a detailed look at common challenges and how to overcome them.
Problem: Incorrectly configuring permission policies can prevent the iframe from accessing WebAuthn APIs.
“NotAllowedError - The 'publickey-credentials-create' feature is not enabled in this document. Permissions Policy may be used to delegate Web Authentication capabilities to cross-origin child frames.”
If you don’t add the permission policies correctly, the browser would throw the following error:
Solution:
Permissions-Policy, and the iframe element must include
the matching allow attribute.<meta/> tags: Configure Permissions-Policy on the parent
server response. A <meta http-equiv="Permissions-Policy"> tag is not a reliable way to
delegate WebAuthn features.Permissions-Policy header separates directives
with commas. The iframe allow attribute separates directives with semicolons.*, because
WebAuthn iframe delegation is a powerful capability.Tip: To properly test that your Permission-Policy headers are set correctly, we
recommend to open your browser’s developer tools, access Application (here: in Chrome
developer tools), go to Frames and search for the iframe’s origin (here:
passkeys.eu/). If the Permissions-Policy is set correctly,
publickey-credentials-create and publickey-credentials-get should be listed among the
Allowed Features:
Problem: The cross-origin iframe passkey creation or passkey login does not work, and you see the following error in your browser console.
"NotAllowedError - The origin of the document is not the same as its ancestors."
This error appears when using the Safari browser and trying to create a passkey from within the iframe, as Safari does not support cross-origin iframe passkey creation (see above).
Solution: Here, you cannot really do anything as Safari does not yet support the creation of a passkey from within a cross-origin iframe (yet).
Blocked a frame with origin "https://passkeys.eu" from accessing a frame with origin "https://cross-origin-iframe.vercel.app". Protocols, domains, and ports must match.
This error is not directly connected to passkeys but more to cross-origin iframes in Safari in general. As part of Safari’s / WebKit’s initiative to block third-party cookies or access to LocalStorage in a third-party-context, parts of the JavaScript logic might be broken.
Solution: Avoid relying on unpartitioned third-party cookies inside your iframe. Use
short-lived iframe sessions with SameSite=None, Secure and Partitioned cookies where
supported, consider the Storage Access API where appropriate, and keep a redirect fallback
for browsers or privacy modes that still block the embedded session.
Problem: iframe browser compatibility issues arise when different browsers have varying levels of support for WebAuthn, iframe permissions, and security attributes, leading to inconsistent behavior.
Solution: To mitigate these iframe browser compatibility issues, test the implementation across multiple browsers to ensure compatibility and identify any browser-specific issues.
Steps:
navigator.credentials.get() and navigator.credentials.create() because
browsers may support iframe login but not iframe registration.Problem: The iframe can be configured correctly in the browser, but the server may still accept assertions from an unexpected top-level origin if it only validates the standard WebAuthn challenge and origin.
Solution: Treat clientDataJSON.crossOrigin and clientDataJSON.topOrigin as part of
your iframe security boundary. For intended
iframe flows, require crossOrigin === true and validate topOrigin against an allowlist
where the browser provides it. As Safari does not expose topOrigin as of May 2026,
decide explicitly whether Safari should use a redirect fallback or a stricter iframe setup
based on CSP frame-ancestors, nonce-bound sessions and partner allowlists.
Problem: When using iframes that require passkeys inside native apps, a crucial distinction must be made between first-party and third-party contexts:
In an embedded WebView (EWV) such as WKWebView on iOS or an Android WebView - the calling app has extensive control over the web session (e.g., intercepting requests). This setup typically supports passkeys only if the domain of the passkey (the Relying Party ID) matches the app’s domain (first-party). However, in a third-party scenario - like a payment provider’s cross-origin flow - an embedded WebView generally cannot access the needed passkey credentials because the merchant’s app and the payment provider’s service are different origins. The required “bindings” for passkeys (between domain, credential, and origin) won’t match in the embedded context.
This limitation leads many apps to adopt a system WebView approach (e.g., ASWebAuthenticationSession on iOS or Custom Tabs on Android). System WebViews isolate the third-party site (e.g., payment provider) in a secure, browser-like environment that correctly allows cross-origin passkeys—if the browser itself supports it. Nevertheless, remember that Safari’s existing iframe limitations also apply to ASWebAuthenticationSession, so if Safari does not permit certain passkey operations in third-party iframes, the same will hold true in the system WebView. There is currently no “native” fix; the best practice for complex flows - such as checkouts involving external payment providers - is to open a system WebView rather than an embedded one.
Solution: For payment providers (and other third parties relying on passkeys across domains), carefully plan the integration to ensure the user is taken out of an embedded WebView and into a system one. While it is a less seamless experience than a purely embedded flow, it is often the only way to guarantee that the passkey functionality will work with third-party services.
Integrate passkeys as Payment Provider via 3rd party SDK.
For more details on handling third-party passkeys within native apps and WebViews, check out Payment Provider Passkeys: Third-Party Passkeys Payment SDK.
While the topics discussed above apply to various scenarios, they are particularly important for payment providers, where multi-domain flows (e.g., merchant site and payment gateway) must embed user authentication within cross-origin iframes. In these setups:
pay.provider.com), even if they’re embedded in a merchant’s site.To tackle these challenges and build a secure, seamless experience similar to Apple Pay, payment providers often adopt a hybrid approach - combining iframe-based integration with a redirect fallback for Safari (or older browsers). In some cases, system browser flows (e.g., ASWebAuthenticationSession on iOS) become mandatory if an embedded WebView won’t allow passkeys at all.
For a deep dive into these payment-specific scenarios - including iframe vs. redirect comparisons, native app considerations and best practices for high passkey adoption, see our dedicated article:
Enterprise Passkey Whitepaper. Practical guidance, rollout patterns, and KPIs for passkey programs.
In particular:
Permissions-Policy settings introduced here.This complementary guide provides in-depth strategies for securing transactions, overcoming Safari’s cross-origin restrictions, and optimizing passkey usage in 3rd party contexts. By combining the technical steps in this article with those payment-focused methods, you can deliver a frictionless, phishing-resistant checkout flow directly inside an iframe unlocking the next level of security and UX for online payments.
Integrating passkeys within iframes significantly enhances user authentication by
improving both security and user experience, but only when the iframe is treated as a
high-trust security boundary. The practical checklist is: delegate WebAuthn with
Permissions-Policy, restrict who can frame the authentication endpoint with CSP
frame-ancestors, verify crossOrigin and topOrigin server-side where available, and
establish the parent session with a nonce-bound postMessage() flow.
With these safeguards in place, cross-origin iframes can allow seamless authentication without redirects or pop-ups while preserving the phishing resistance that makes passkeys valuable in the first place.
Real-world implementations, such as Shopify's integration of passkeys within their login component, demonstrate the practical benefits and flexibility of this approach.
Corbado is the Passkey Intelligence Platform for CIAM teams running consumer authentication at scale. We help you see what IDP logs and generic analytics tools can't: which devices, OS versions, browsers and credential managers support passkeys, why enrollments don't turn into logins, where the WebAuthn flow fails and when an OS / browser update silently breaks login, all without replacing Okta, Auth0, Ping, Cognito or your in-house IDP. Two products: Corbado Observe layers observability for passkeys and any other login method. Corbado Connect adds managed passkeys with analytics built in (alongside your IDP). VicRoads runs passkeys for 5M+ users with Corbado (+80% passkey activation). Talk to a Passkey Expert →
Related Articles
Table of Contents