WebAuthnのImmediate Mediationを深掘り解説。単一のサインインボタンを実現し、紛らわしいQRコードを回避して、よりスマートなログインフローを構築する仕組みを紹介します。
Vincent
Created: August 8, 2025
Updated: August 13, 2025
See the original blog version in English here.
60-page Enterprise Passkey Whitepaper:
Learn how leaders get +80% passkey adoption. Trusted by Rakuten, Klarna & Oracle
パスキーへの移行は、「パスキーのパラドックス」を生み出しています。一部のユーザーはパスキーを持っていますが、多くのユーザーはまだ従来のパスワードを使用しています。これにより、「パスワードでサインイン」「Googleでサインイン」「パスキーでサインイン」といった複数のボタンがログイン画面に乱立してしまいます。この断片化はフリクション(抵抗)を引き起こします。ユーザーが新しいデバイスで「パスキーでサインイン」をクリックしても、パスキーがローカルで利用できないために、紛らわしいQRコードのプロンプトに直面することがあります。根本的な問題は、ウェブサイトが認証フローを開始する前にユーザーの状況を把握できない点にあります。
一つの解決策は、IDファースト(identifier-first)のアプローチを取り、ユーザーにとって最適なログイン方法を判断することです。もう一つの潜在的な解決策は、各ユーザーにとって最もスムーズなフローを調整する、単一のインテリジェントな「サインイン」ボタンです。このボタンは、デバイス上でパスキーが利用可能であれば直接パスキーを要求し、そうでなければ他の方法にスムーズにフォールバックするべきです。
これを可能にする新しいWebAuthn機能が発表されました。それがImmediate Mediation
(mediation: 'immediate'
) です。WebAuthn
API呼び出しでこのプロパティを設定することで、開発者はパスキーのパラドックスを解決する、インテリジェントで統一されたサインイン体験を構築できます。この記事では、mediation: 'immediate'
とは何か、どのように機能するのか、そしてどう実装するのかについて、開発者向けに詳しく解説します。
Immediate Mediationを理解するためには、まず他の選択肢を知っておくと役立ちます。WebAuthnにおけるユーザーメディエーションとは、ブラウザがウェブサイト(リライングパーティ)とユーザーの認証器(例:Face ID、YubiKey)との間のやり取りをどのように管理するかということです。
これは古典的で明示的なWebAuthnフローです。リライングパーティがmediation
設定を指定せずにnavigator.credentials.get()
を呼び出すと、ブラウザは常にモーダルダイアログを表示します。このダイアログはページコンテンツの上に重なり、ユーザーの即時的な注意を要求し、ウェブサイトとの他のすべての対話を一時停止させます。
mediation: 'conditional'
#ユーザーのパスキーへの移行を支援するために導入されたこのモードは、よりさりげないものです。mediation: 'conditional'
を使用すると、WebAuthnリクエストはautocomplete="webauthn"
属性を持つ入力フィールド(例:ユーザー名)に紐付けられます。ユーザーがそのフィールドをクリックすると、ブラウザの自動入力UIが利用可能なパスキーを提案します。
mediation: 'immediate'
は、「単一のサインインボタン」問題の解決策です。これは、ウェブサイトがUIを表示する前にパスキーが利用可能かどうかを確実にチェックする方法を提供します。
immediate
メディエーションは、モーダルでユーザーにパスキーでの認証を指示するのではなく、ブラウザにこう尋ねます。「このユーザーのために、このデバイスで今すぐ利用できるパスキーはありますか?」
重要なのは、このクエリがローカルで利用可能なクレデンシャル(例:デバイス上の認証器であるWindows Helloやパスワードマネージャー経由で同期されたパスキー)のみをチェックすることです。これは、一般的なフリクションの原因であるクロスデバイスのQRコードフローのトリガーを回避するように設計されています。
この機能の力は、その明確で二者択一の結果にあります。navigator.credentials.get()
から返されるPromiseは成功するか失敗するかのどちらかであり、開発者に明確なシグナルを与えます。
PublicKeyCredential
オブジェクトで解決されます。navigator.credentials.get()
のPromiseはNotAllowedError
という名前のDOMException
で即座にリジェクトされます。NotAllowedError
はバグではありません。むしろ機能のようなものです。これは、ウェブサイトが代替の認証方法に進むべきだという、信頼性が高く瞬時のシグナルです。これにより、開発者は単純なtry...catch
ブロックを使用できます。try
ブロックはシームレスなパスキーフローを試み、catch
ブロックはNotAllowedError
をリッスンして従来のログインフォームをレンダリングします。これにより、ユーザーの状況にインテリジェントに適応する単一のエントリーポイントを作成することで、単一サインインボタンの問題をエレガントに解決します。
適切なメディエーションモードを選択することは、重要なUXの決定です。この表は、並べて比較したものです。
機能 / 動作 | モーダル(デフォルト) | 条件付きUI (conditional ) | Immediate (immediate ) |
---|---|---|---|
API呼び出し | navigator.credentials.get() | navigator.credentials.get({ mediation: 'conditional' }) | navigator.credentials.get({ mediation: 'immediate' }) |
トリガー | 明示的なユーザー操作(例:ボタンクリック) | ページ読み込み時、入力フィールドのフォーカスでUI表示 | 明示的なユーザー操作(例:ボタンクリック) |
UI表示 | 常にモーダルダイアログを即座に表示 | 非モーダルな自動入力スタイルのUIを表示 | ローカルクレデンシャルが見つかった場合にのみ、モーダルダイアログを表示 |
ローカルクレデンシャルがない場合の動作 | クロスデバイスフロー用のUIを表示(例:QRコード) | Promiseは保留状態のままで解決されず、エラーもスローされない | PromiseはNotAllowedError で即座にリジェクトされる |
サイトが得る情報 | ユーザーがフローを完了するまで何も学習しない | ユーザーが操作しない場合は何も学習しない。最高のプライバシー | ローカルクレデンシャルが存在するかどうかという1ビットの情報を学習する |
主なユースケース | 専用の「パスキーでサインイン」ボタン。明示的な2FA | 統一されたサインイン/サインアップフォーム。パスワードフォームの段階的な強化 | 混合ユーザーベース向けの単一の主要な「サインイン」ボタン |
開発者のアクション | 成功またはユーザーのキャンセルを処理 | 成功を処理。対処すべき失敗シグナルなし | 成功またはNotAllowedError を処理してフォールバックUIをトリガー |
ここでは、mediation: 'immediate'
を実装するための実践的なステップバイステップガイドを紹介します。
mediation: 'immediate'
は新しい機能であるため、堅牢な機能検出が不可欠です。
// 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()
の呼び出し#この呼び出しは、ボタンのクリックなど、ユーザーのジェスチャーによってトリガーされる必要があります。
// 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
の処理#catch
ブロックは、単一サインインボタンの「インテリジェンス」が実現される場所です。
// 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); } }
最もシームレスな体験のために、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
リクエスト(多くの場合、ページ読み込み時に開始される)は、新しいimmediate
リクエストをブロックする可能性があります。新しいリクエストを開始する前に、保留中のリクエストをキャンセルするためにAbortController
を使用することを検討してください。allowCredentials
の制限:
allowCredentials
配列は空でなければなりません。クレデンシャルIDを提供すると、呼び出しは失敗します。これは、サイトが特定の既知のユーザーをチェックするのを防ぐための重要なプライバシー保護策です。mediation: 'immediate'
は、そのセキュリティとプライバシーのトレードオフを明確に理解した上で設計されました。
中心的なトレードオフは「1ビットリーク」です。リライングパーティは、Promiseの解決タイミングを計ることで、1ビットの情報、つまりPromiseが即座にリジェクトされたか(ローカルクレデンシャルなし)、遅延したか(ローカルクレデンシャルが見つかったためUIプロンプトが表示された)を推測できます。このリークの目的は、より良いUXを実現することです。
設計者は、悪用(例:ユーザートラッキング)の可能性を予測し、いくつかの譲れない保護策を組み込みました。
allowCredentials
リスト:
allowCredentials
配列は空でなければなりません。これにより、サイトがこの機能を使用して特定の既知のユーザーが訪問しているかどうかを確認するのを防ぎます。iframe
)では許可されません。これらの緩和策により、WebAuthnの中核的なセキュリティ保証は損なわれないことが保証されます。認証セレモニー自体は変更されず、フィッシング耐性を維持します。
mediation: 'immediate'
はWebAuthn Level 3仕様の高度な機能であり、その展開は進行中です。2025年半ばの時点では、プログレッシブエンハンスメント戦略が不可欠です。
ブラウザ | ステータス | 注記とソース |
---|---|---|
Chrome | 開発者トライアル | experimental-web-platform-features フラグ経由で利用可能。トラッキングバグ。 |
Edge | 開発中(予定) | Chromiumベースのブラウザとして、サポートはChromeに追随するはずです。 |
Safari (WebKit) | 検討中 | WebKit Standards Positions。公式なコミットメントなし。 |
Firefox (Gecko) | 検討中 | Mozilla Standards Positions。公式なコミットメントなし。 |
mediation: 'immediate'
は、よりスマートなログインボタンのための優れた低レベルツールを提供しますが、Corbadoが提供するような、より広範な「Passkey Intelligence」ソリューションとは区別することが重要です。どちらもパスキーのパラドックスを解決し、採用を増やすことを目指していますが、その方法は異なります。
機能 | mediation: 'immediate' | Passkey Intelligence(例:Corbado) |
---|---|---|
仕組み | 現在のデバイスでローカルに利用可能なパスキーをチェックするブラウザネイティブのAPI呼び出し。 | ユーザーデバイス、認証器、セッションをまたいだログイン履歴に関するデータを収集・分析するバックエンドサービス。 |
提供されるシグナル | 単純なバイナリシグナル:ローカルパスキーが存在する(UIプロンプト )か、存在しない(NotAllowedError )か。 | 「このユーザーは、よく使うパスキー対応デバイスでパスワードでログインしたばかりです」といった、リッチで文脈的なインサイト。 |
主な利点 | ネットワークオーバーヘッドが最小限の、非常に高速なネイティブチェック。 | 新しいWebAuthn機能のブラウザ/OSサポートに依存しない普遍的な利用可能性。よりカスタマイズされたUXのための深いインサイト。 |
主な依存関係 | 最新のブラウザとOSのサポートが必要ですが、まだ普遍的ではありません。 | バックエンドサービスとの統合。 |
Passkey Intelligenceは、時間をかけてデータを収集・評価することで、さらに一歩進んでいます。これにより、より洗練されたタイムリーなユーザー介入が可能になります。例えば、Passkey Intelligenceバックエンドは以下を検出できます。
このデータ駆動型アプローチは、mediation: 'immediate'
のブラウザサポートに依存しないため、すべてのユーザーに対して、今すぐよりインテリジェントなログインフローを提供できます。
両方の長所を活かす
最終的に、これら2つのアプローチは相互に排他的ではなく、補完的です。理想的な解決策は、これらを組み合わせることです。
mediation: 'immediate'
をシグナルの一つとして使用し、迅速な初期チェックを実行できます。mediation: 'immediate'
のネイティブな速度とPasskey Intelligenceバックエンドの深いインサイトを組み合わせることで、最もシームレスで適応性があり、効果的なログイン体験を提供し、すべてのユーザーをパスワードレスの未来へと優しく導くことができます。
Immediate Mediationは、ログイン体験を大幅に向上させます。これは、パスキーへの移行中にユーザーが直面する一般的なフリクションや混乱のポイントを排除するために必要なインテリジェンスを提供します。
immediate
メディエーションはユーザーの認知的負荷を取り除きます。ユーザーは、どの認証方法を設定したかを覚えたり、雑然とした選択肢のリストから選んだりする必要がなくなります。ログインプロセスはよりシンプルで直感的になります。mediation: 'immediate'
はローカルクレデンシャルのみを探すため、この混乱を招く状態を完全に回避します。ユーザーがフローを中断する代わりに、アプリケーションは明確なシグナル(NotAllowedError
)を受け取り、別の方法にスムーズにフォールバックできるため、よりスムーズな体験につながります。Immediate Mediationは、パスキー移行期間の断片化されたログイン体験を解決する新しいWebAuthn機能です。これにより、ユーザーの状況に適応する単一のインテリジェントな「サインイン」ボタンの作成が可能になり、混乱とフリクションを排除します。計算されたプライバシーのトレードオフを導入しますが、WebAuthnの中核的なセキュリティを損なうことなくリスクを軽減するための堅牢な保護策が含まれています。
開発者にとって、今後の道はプログレッシブエンハンスメントです。堅実なベースライン体験を構築し、サポートされているブラウザ向けにimmediate
メディエーションをその上に重ねます。この機能を採用することは、パスキーの採用を加速し、セキュリティを強化し、運用コストを削減し、コンバージョンを向上させるための戦略的な動きです。
これらの高度な認証フローの実装は複雑になる可能性があります。Corbadoのエンタープライズパスキープラットフォームは、この複雑さを抽象化します。当社のインフラストラクチャは、条件付きおよびimmediate
メディエーションを含む最適なフローのオーケストレーションを処理し、お客様のチームが最先端でフリクションレスな認証体験を自信を持って展開できるようにします。
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
Table of Contents