A deep dive into WebAuthn immediate mediation. Learn how it creates a single sign-in button, avoids confusing QR codes & builds a smarter login flow.
Vincent
Created: June 20, 2025
Updated: June 20, 2025
60-page Enterprise Passkey Whitepaper:
Learn how leaders get +80% passkey adoption. Trusted by Rakuten, Klarna & Oracle
The transition to passkeys is creating a "passkey paradox": some users have passkeys, while many still use traditional passwords. This leads to cluttered login screens with multiple buttons: "Sign in with Password", "Sign in with Google" and "Sign in with Passkey". This fragmentation causes friction. A user might click "Sign in with Passkey" on a new device only to face a confusing QR code prompt because their passkey isn't locally available. The core problem is the website's inability to know the user's context before initiating an authentication flow.
One solution is going identifier-first and determining the best login method for the user. Another potential solution is a single, intelligent "Sign In" button that orchestrates the most seamless flow for each user. It should directly prompt for a passkey if one is available on the device, or gracefully fall back to other methods if not.
There is a new WebAuthn feature announced that could make this possible: Immediate
Mediation (mediation: 'immediate'
). By setting this property in a WebAuthn API call,
developers can build an intelligent, unified sign-in experience that solves the passkey
paradox. This article provides a developer-focused analysis into mediation: 'immediate'
,
exploring what it is, how it works, and how to implement it.
To understand Immediate Mediation, it's helpful to first know the other options. User mediation in WebAuthn is how the browser manages the interaction between your website (the Relying Party) and the user's authenticator (e.g., Face ID, YubiKey).
This is the classic, explicit WebAuthn flow. When a
Relying Party calls navigator.credentials.get()
without
specifying a mediation
preference, the browser always presents a modal dialog. This
dialog overlays the page content, demanding the user's immediate attention and pausing all
other interaction with the website.
mediation: 'conditional'
#Introduced to help users
transition to passkeys, this mode is
more subtle. With mediation: 'conditional'
, the WebAuthn request is attached to an input
field (e.g., username) with the autocomplete="webauthn"
attribute. When the user clicks
the field, the browser's autofill UI suggests any available passkeys.
mediation: 'immediate'
is the solution for the "single sign-in button" problem. It
provides a reliable way for a website to check for a passkey's availability before showing
any UI.
Instead of telling the user to authenticate with a passkey via a modal, immediate
mediation asks the browser: "Is there a passkey readily available for this user on this
device right now?"
Crucially, this query only checks for locally-available credentials (e.g., on-device authenticators like Windows Hello or passkeys synced via a password manager). It is designed to avoid triggering the cross-device QR code flow, which is a common friction point.
The power of this feature lies in its clear, binary outcome. The promise returned by
navigator.credentials.get()
will either succeed or fail, giving the developer a clear
signal.
PublicKeyCredential
object.navigator.credentials.get()
promise
immediately rejects with a DOMException
named NotAllowedError
.The NotAllowedError
is not a bug. It's more like a feature. It is a reliable,
instantaneous signal that the website should proceed with a fallback authentication
method. This allows developers to use a simple try...catch
block: the try
block
attempts the seamless
passkey flow, and the
catch
block listens for NotAllowedError
to render a traditional login form. It
elegantly solves the single sign-in button problem by creating one entry point that
intelligently adapts to the user's context.
Choosing the right mediation mode is a critical UX decision. This table provides a side-by-side comparison.
Feature / Behavior | Modal (Default) | Conditional UI (conditional ) | Immediate (immediate ) |
---|---|---|---|
API Call | navigator.credentials.get() | navigator.credentials.get({ mediation: 'conditional' }) | navigator.credentials.get({ mediation: 'immediate' }) |
Trigger | Explicit user action (e.g., button click) | Page load; UI on input field focus | Explicit user action (e.g., button click) |
UI Presentation | Always shows a modal dialog immediately. | Shows a non-modal, autofill-style UI. | Only if a local credential is found, then shows a modal dialog. |
Behavior if No Local Credential | Shows UI for cross-device flows (e.g., QR code). | Promise remains pending, never resolves, no error thrown. | Promise immediately rejects with NotAllowedError . |
Site Knowledge | Learns nothing until user completes flow. | Learns nothing if user doesn't interact. Highest privacy. | Learns one bit of info: whether a local credential exists. |
Primary Use Case | Dedicated "Sign in with Passkey" button. Explicit 2FA. | Unified sign-in/sign-up forms. Progressively enhancing password forms. | A single, primary "Sign In" button for a mixed user base. |
Developer Action | Handle success or user cancellation. | Handle success. No failure signal to act upon. | Handle success or NotAllowedError to trigger a fallback UI. |
Here is a practical, step-by-step guide to implementing mediation: 'immediate'
.
Since mediation: 'immediate'
is a new feature, robust feature detection is crucial.
// Feature detection is essential for progressive enhancement. let immediateMediationAvailable = false; if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) { try { const capabilities = await PublicKeyCredential.getClientCapabilities(); // The 'immediateGet' capability signals browser support. immediateMediationAvailable = capabilities.immediateGet === true; } catch (e) { console.error("Error getting client capabilities:", e); } }
navigator.credentials.get()
Call#This call must be triggered by a user gesture, like a button click.
// This function should be the event handler for your primary "Sign In" button. async function handleSignInClick() { if (!immediateMediationAvailable) { // Fall back to showing a legacy login form if the feature isn't supported. showLegacyLoginForm(); return; } try { // Fetch a fresh, random challenge from your server for each attempt. const challenge = await fetchChallengeFromServer(); const publicKeyCredentialRequestOptions = { challenge: challenge, // The server-provided challenge as a Uint8Array rpId: "example.com", // The allowCredentials list MUST be empty for immediate mediation // to protect user privacy. allowCredentials: [], }; const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, // This is the key that enables the immediate mediation flow. mediation: "immediate", }); // If the promise resolves, send the credential to your server for verification. await verifyCredentialOnServer(credential); } catch (error) { // The catch block is a critical part of the control flow. handleAuthError(error); } }
NotAllowedError
for Graceful Fallback#The catch
block is where the "intelligence" of the single sign-in button is realized.
// Handling the NotAllowedError is the key to the fallback mechanism. function handleAuthError(error) { // Check the 'name' property of the DOMException. if (error.name === "NotAllowedError") { // This is the expected signal to show the traditional login form. console.log("No local passkey found. Showing legacy login form."); showLegacyLoginForm(); } else { // This handles other potential errors, like the user dismissing the prompt. console.error("Authentication error:", error); } }
For the most seamless experience, you can ask the browser to search for both passkeys and
saved passwords in the same request by adding password: true
.
// Combining passkeys and passwords for a truly unified sign-in experience. const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, password: true, // Ask the browser to include saved passwords. mediation: "immediate", }); // The returned 'credential' object will either be a PublicKeyCredential // or a PasswordCredential. Your server-side logic must handle both.
conditional
request (often started on
page load) can block a new immediate
request. Consider using an AbortController
to
cancel any pending requests before starting a new one.allowCredentials
Restriction: The allowCredentials
array must be empty.
Providing credential IDs will cause the call to fail. This is a crucial privacy
safeguard to prevent sites from checking for specific, known users.mediation: 'immediate'
was designed with a clear understanding of its security and
privacy trade-offs.
The core trade-off is a "one-bit leak." By timing the promise's resolution, a Relying Party can infer one bit of information: whether the promise rejected instantly (no local credential) or was delayed (a UI prompt was shown because a local credential was found). The purpose of this leak is to enable a better UX.
The designers anticipated the potential for abuse (e.g., user tracking) and built-in several non-negotiable safeguards:
allowCredentials
List: The allowCredentials
array must be empty. This
prevents a site from using this feature to check if a specific known user is
visiting.iframe
from another origin) to prevent cross-site tracking.These mitigations ensure that the core security guarantees of WebAuthn remain untouched. The authentication ceremony itself is unchanged and remains phishing-resistant.
mediation: 'immediate'
is an advanced feature from the
WebAuthn Level 3 specification, and its rollout is
ongoing. As of mid-2025, a progressive enhancement strategy is essential.
Browser | Status | Notes & Source |
---|---|---|
Chrome | Developer Trial | Available via the experimental-web-platform-features flag. Tracking bug. |
Edge | In Development (Expected) | As a Chromium browser, support should follow Chrome. |
Safari (WebKit) | Under Consideration | WebKit Standards Positions. No public commitment. |
Firefox (Gecko) | Under Consideration | Mozilla Standards Positions. No public commitment. |
While mediation: 'immediate'
provides a great, low-level tool for a smarter login
button, it's important to distinguish it from a broader
"Passkey Intelligence"
solution, such as the one offered by Corbado. Both aim to solve the passkey paradox and
increase adoption, but they do so in different ways.
Feature | mediation: 'immediate' | Passkey Intelligence (e.g., Corbado) |
---|---|---|
How it Works | A browser-native API call that checks for locally available passkeys on the current device. | A backend service that collects and analyzes data about user devices, authenticators, and login history across sessions. |
Signal Provided | A simple, binary signal: a local passkey either exists (UI prompt ) or it doesn't (NotAllowedError ). | Rich, contextual insights, e.g., "This user just logged in with a password on a passkey-capable device they often use." |
Key Advantage | Very fast, native check with minimal network overhead. | Universal availability, independent of browser/OS support for new WebAuthn features. Deeper insights for more tailored UX. |
Main Dependency | Requires up-to-date browser and OS support, which is not yet universal. | Integration with a backend service. |
Passkey Intelligence goes a step further by collecting and evaluating data over time. This allows for more sophisticated and timely user interventions. For example, a Passkey Intelligence backend can detect:
This data-driven approach is independent of browser support for mediation: 'immediate'
,
meaning it can provide a more intelligent login flow for all your users, right now.
The Best of Both Worlds
Ultimately, these two approaches are not mutually exclusive; they are complementary. The ideal solution combines them:
mediation: 'immediate'
as one of its signals on supported
browsers to perform a quick, initial check.By combining the native speed of mediation: 'immediate'
with the deep insights of a
Passkey Intelligence
backend, you can provide the most seamless, adaptive, and effective login experience
possible, gently guiding every user towards a passwordless future.
Immediate Medation is great upgrade to the login experience. It provides the intelligence needed to eliminate common points of friction and confusion for users during the transition to passkeys.
immediate
mediation
removes the cognitive load for the user. They no longer have to remember which
authentication method they set up or choose from a cluttered list of options. The login
process becomes simpler and more intuitive.mediation: 'immediate'
only looks for local
credentials, it avoids this confusing state entirely. Instead of the user aborting the
flow, the application receives a clear signal (NotAllowedError
) to gracefully fall
back to another method, resulting in a smoother journey.Immediate Mediation is a new WebAuthn feature that solves the fragmented login experience of the passkey transition period. It enables the creation of a single, intelligent "Sign In" button that adapts to the user's context, eliminating confusion and friction. While it introduces a calculated privacy trade-off, it includes robust safeguards to mitigate risks without compromising the core security of WebAuthn.
For developers, the path forward is progressive enhancement. Build a solid baseline
experience, and layer immediate
mediation on top for supported browsers. Adopting this
feature is a strategic move to accelerate
passkey adoption, enhance security, lower
operational costs, and improve conversion.
Implementing these advanced authentication flows can be complex. Corbado's Enterprise
Passkey Platform abstracts away this complexity. Our
infrastructure handles optimal flow
orchestration—including conditional and immediate
mediation allowing your team to deploy
a state-of-the-art, frictionless authentication experience with confidence.
Enjoyed this read?
🤝 Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.
🚀 Subscribe to Substack
Get the latest news, strategies, and insights about passkeys sent straight to your inbox.
Related Articles
Chrome Conditional UI: isConditional MediationAvailable() Returns True on Windows 10
Vincent - March 22, 2024
WebAuthn Conditional UI (Passkeys Autofill) Technical Explanation
Vincent - October 20, 2023
Table of Contents