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 코드 프롬프트에 직면할 수 있습니다. 핵심 문제는 웹사이트가 인증 흐름을 시작하기 전에 사용자의 컨텍스트를 알 수 없다는 점입니다.
한 가지 해결책은 식별자 우선 방식을 채택하여 사용자에게 가장 적합한 로그인 방법을 결정하는 것입니다. 또 다른 잠재적 해결책은 각 사용자에게 가장 원활한 흐름을 조율하는 지능적인 단일 '로그인' 버튼입니다. 이 버튼은 기기에서 패스키를 사용할 수 있는 경우 직접 패스키를 요청하고, 그렇지 않은 경우 다른 방법으로 자연스럽게 대체되어야 합니다.
이를 가능하게 할 새로운 WebAuthn 기능이 발표되었습니다. 바로 즉시
중재(mediation: 'immediate'
)입니다. 개발자는 WebAuthn API 호출에서 이 속성을
설정함으로써 패스키 역설을 해결하는 지능적이고 통합된 로그인 환경을 구축할 수 있습니다. 이
글에서는 개발자 관점에서 mediation: 'immediate'
가 무엇인지, 어떻게 작동하는지, 그리고
어떻게 구현하는지 심층적으로 분석합니다.
즉시 중재를 이해하려면 먼저 다른 옵션들을 아는 것이 도움이 됩니다. WebAuthn의 사용자 중재는 브라우저가 웹사이트(신뢰 당사자)와 사용자 인증자(예: Face ID, YubiKey) 간의 상호작용을 관리하는 방식입니다.
이것은 고전적이고 명시적인 WebAuthn 흐름입니다.
신뢰 당사자(Relying Party)가 mediation
선호도를 지정하지 않고
navigator.credentials.get()
을 호출하면, 브라우저는 항상 모달 대화상자를 표시합니다.
이 대화상자는 페이지 콘텐츠 위에 나타나 사용자의 즉각적인 주의를 요구하며 웹사이트와의
다른 모든 상호작용을 일시 중지시킵니다.
mediation: 'conditional'
#사용자들이 패스키로 전환하는 것을 돕기
위해 도입된 이 모드는 더 미묘합니다. mediation: 'conditional'
을 사용하면 WebAuthn 요청이
autocomplete="webauthn"
속성을 가진 입력 필드(예: 사용자 이름)에 연결됩니다. 사용자가
필드를 클릭하면 브라우저의 자동 완성 UI가 사용 가능한 패스키를 제안합니다.
mediation: 'immediate'
는 '단일 로그인 버튼' 문제에 대한 해결책입니다. 이는 웹사이트가
UI를 표시하기 전에 패스키의 사용 가능 여부를 안정적으로 확인할 수 있는 방법을 제공합니다.
immediate
중재는 모달을 통해 사용자에게 패스키로 인증하라고 _지시_하는 대신,
브라우저에 _질문_합니다. "지금 바로 이 기기에서 이 사용자를 위해 즉시 사용 가능한
패스키가 있나요?"
중요한 점은 이 쿼리가 로컬에서 사용 가능한 자격 증명(예: Windows Hello와 같은 기기 내 인증자 또는 비밀번호 관리자를 통해 동기화된 패스키)만 확인한다는 것입니다. 이는 흔한 마찰 지점인 기기 간 QR 코드 흐름을 피하도록 설계되었습니다.
이 기능의 힘은 명확한 이진 결과에 있습니다. navigator.credentials.get()
이 반환하는
promise는 성공하거나 실패하여 개발자에게 명확한 신호를 줍니다.
PublicKeyCredential
객체로 확인(resolve)됩니다.navigator.credentials.get()
promise는
NotAllowedError
라는 이름의 DOMException
으로 즉시 거부됩니다.NotAllowedError
는 버그가 아닙니다. 오히려 기능에 가깝습니다. 이는 웹사이트가 대체 인증
방법으로 진행해야 한다는 안정적이고 즉각적인 신호입니다. 이를 통해 개발자는 간단한
try...catch
블록을 사용할 수 있습니다. try
블록은 원활한 패스키 흐름을 시도하고,
catch
블록은 NotAllowedError
를 수신하여 전통적인 로그인 양식을 렌더링합니다. 이는
사용자의 컨텍스트에 지능적으로 적응하는 단일 진입점을 만들어 단일 로그인 버튼 문제를
우아하게 해결합니다.
올바른 중재 모드를 선택하는 것은 중요한 UX 결정입니다. 이 표는 각 모드를 나란히 비교합니다.
기능 / 동작 | 모달 (기본값) | 조건부 UI (conditional ) | 즉시 (immediate ) |
---|---|---|---|
API 호출 | navigator.credentials.get() | navigator.credentials.get({ mediation: 'conditional' }) | navigator.credentials.get({ mediation: 'immediate' }) |
트리거 | 명시적인 사용자 행동 (예: 버튼 클릭) | 페이지 로드, 입력 필드 포커스 시 UI 표시 | 명시적인 사용자 행동 (예: 버튼 클릭) |
UI 표시 | 항상 즉시 모달 대화상자를 표시함. | 비모달, 자동 완성 스타일의 UI를 표시함. | 로컬 자격 증명이 발견된 경우에만 모달 대화상자를 표시함. |
로컬 자격 증명이 없을 경우의 동작 | 기기 간 흐름(예: QR 코드)을 위한 UI를 표시함. | Promise가 대기 상태로 남아 해결되지 않으며, 오류가 발생하지 않음. | Promise가 NotAllowedError 와 함께 즉시 거부됨. |
사이트가 알게 되는 정보 | 사용자가 흐름을 완료할 때까지 아무것도 알 수 없음. | 사용자가 상호작용하지 않으면 아무것도 알 수 없음. 가장 높은 개인 정보 보호 수준. | 로컬 자격 증명 존재 여부라는 1비트 정보를 알게 됨. |
주요 사용 사례 | 전용 '패스키로 로그인' 버튼. 명시적 2FA. | 통합된 로그인/가입 양식. 비밀번호 양식의 점진적 개선. | 혼합된 사용자 기반을 위한 단일 기본 '로그인' 버튼. |
개발자 조치 | 성공 또는 사용자 취소 처리. | 성공 처리. 조치할 실패 신호 없음. | 성공 또는 NotAllowedError 를 처리하여 대체 UI 트리거. |
다음은 mediation: 'immediate'
를 구현하기 위한 실용적인 단계별 가이드입니다.
mediation: 'immediate'
는 새로운 기능이므로 강력한 기능 감지가 중요합니다.
// 기능 감지는 점진적 향상을 위해 필수적입니다. let immediateMediationAvailable = false; if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) { try { const capabilities = await PublicKeyCredential.getClientCapabilities(); // 'immediateGet' 기능은 브라우저 지원을 나타냅니다. immediateMediationAvailable = capabilities.immediateGet === true; } catch (e) { console.error("클라이언트 기능 가져오기 오류:", e); } }
navigator.credentials.get()
호출#이 호출은 버튼 클릭과 같은 사용자 제스처에 의해 트리거되어야 합니다.
// 이 함수는 기본 '로그인' 버튼의 이벤트 핸들러여야 합니다. async function handleSignInClick() { if (!immediateMediationAvailable) { // 기능이 지원되지 않는 경우 기존 로그인 양식을 표시하는 것으로 대체합니다. showLegacyLoginForm(); return; } try { // 각 시도마다 서버에서 새로운 무작위 챌린지를 가져옵니다. const challenge = await fetchChallengeFromServer(); const publicKeyCredentialRequestOptions = { challenge: challenge, // 서버에서 제공한 챌린지 (Uint8Array) rpId: "example.com", // 사용자 개인 정보 보호를 위해 즉시 중재에서는 // allowCredentials 목록이 비어 있어야 합니다. allowCredentials: [], }; const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, // 이것이 즉시 중재 흐름을 활성화하는 핵심입니다. mediation: "immediate", }); // promise가 확인되면, 확인을 위해 자격 증명을 서버로 보냅니다. await verifyCredentialOnServer(credential); } catch (error) { // catch 블록은 제어 흐름의 중요한 부분입니다. handleAuthError(error); } }
NotAllowedError
처리#catch
블록은 단일 로그인 버튼의 '지능'이 실현되는 곳입니다.
// NotAllowedError를 처리하는 것이 대체 메커니즘의 핵심입니다. function handleAuthError(error) { // DOMException의 'name' 속성을 확인합니다. if (error.name === "NotAllowedError") { // 이것이 전통적인 로그인 양식을 표시하라는 예상된 신호입니다. console.log("로컬 패스키를 찾을 수 없습니다. 기존 로그인 양식을 표시합니다."); showLegacyLoginForm(); } else { // 사용자가 프롬프트를 닫는 것과 같은 다른 잠재적 오류를 처리합니다. console.error("인증 오류:", error); } }
가장 원활한 경험을 위해, password: true
를 추가하여 브라우저가 동일한 요청에서 패스키와
저장된 비밀번호를 모두 검색하도록 요청할 수 있습니다.
// 진정으로 통합된 로그인 경험을 위해 패스키와 비밀번호를 결합합니다. const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, password: true, // 브라우저에 저장된 비밀번호를 포함하도록 요청합니다. mediation: "immediate", }); // 반환된 'credential' 객체는 PublicKeyCredential 또는 // PasswordCredential이 됩니다. 서버 측 로직은 둘 다 처리해야 합니다.
conditional
요청(종종 페이지 로드 시 시작됨)이
새로운 immediate
요청을 차단할 수 있습니다. 새 요청을 시작하기 전에
AbortController
를 사용하여 보류 중인 요청을 취소하는 것을 고려하세요.allowCredentials
제한: allowCredentials
배열은 반드시 비어 있어야 합니다.
자격 증명 ID를 제공하면 호출이 실패합니다. 이는 사이트가 특정, 알려진 사용자를 확인하는
것을 방지하기 위한 중요한 개인 정보 보호 장치입니다.mediation: 'immediate'
는 보안 및 개인 정보 보호의 장단점을 명확히 이해하고
설계되었습니다.
핵심적인 장단점은 '원비트 유출(one-bit leak)'입니다. 신뢰 당사자(Relying Party)는 promise의 확인 시간을 측정함으로써 한 비트의 정보를 추론할 수 있습니다. 즉, promise가 즉시 거부되었는지(로컬 자격 증명 없음) 또는 지연되었는지(로컬 자격 증명이 발견되어 UI 프롬프트가 표시됨)를 알 수 있습니다. 이 유출의 목적은 더 나은 UX를 가능하게 하는 것입니다.
설계자들은 사용자 추적과 같은 잠재적 남용을 예상하고 여러 가지 타협 불가능한 안전장치를 내장했습니다.
allowCredentials
목록: allowCredentials
배열은 비어 있어야 합니다. 이는
사이트가 이 기능을 사용하여 특정 알려진 사용자가 방문했는지 확인하는 것을 방지합니다.iframe
)에서 허용되지 않습니다.이러한 완화 조치는 WebAuthn의 핵심 보안 보장이 손상되지 않도록 보장합니다. 인증 절차 자체는 변경되지 않으며 피싱(phishing)에 강한 상태를 유지합니다.
mediation: 'immediate'
는 WebAuthn Level 3 사양의 고급
기능이며, 출시는 계속 진행 중입니다. 2025년 중반 현재, 점진적 향상 전략이 필수적입니다.
브라우저 | 상태 | 참고 및 출처 |
---|---|---|
Chrome | 개발자 평가판 | experimental-web-platform-features 플래그를 통해 사용 가능. 추적 버그. |
Edge | 개발 중 (예상) | Chromium 브라우저이므로 Chrome을 따라 지원될 것으로 예상됨. |
Safari (WebKit) | 검토 중 | WebKit 표준 입장. 공개적인 약속 없음. |
Firefox (Gecko) | 검토 중 | Mozilla 표준 입장. 공개적인 약속 없음. |
mediation: 'immediate'
가 더 스마트한 로그인 버튼을 위한 훌륭한 저수준 도구를 제공하지만,
Corbado가 제공하는 것과 같은 더 넓은
'패스키 인텔리전스(Passkey Intelligence)'
솔루션과 구별하는 것이 중요합니다. 둘 다 패스키 역설을 해결하고 채택률을 높이는 것을
목표로 하지만, 다른 방식으로 이를 수행합니다.
기능 | mediation: 'immediate' | 패스키 인텔리전스 (예: Corbado) |
---|---|---|
작동 방식 | 현재 기기에서 로컬로 사용 가능한 패스키를 확인하는 브라우저 네이티브 API 호출. | 여러 세션에 걸쳐 사용자 기기, 인증자, 로그인 기록에 대한 데이터를 수집하고 분석하는 백엔드 서비스. |
제공되는 신호 | 로컬 패스키가 존재하거나(UI 프롬프트 ) 존재하지 않는다는(NotAllowedError ) 간단한 이진 신호. | "이 사용자는 방금 패스키 지원 기기에서 비밀번호로 로그인했습니다."와 같은 풍부하고 맥락적인 통찰력. |
주요 이점 | 최소한의 네트워크 오버헤드로 매우 빠른 네이티브 확인. | 새로운 WebAuthn 기능에 대한 브라우저/OS 지원과 무관하게 보편적으로 사용 가능. 더 맞춤화된 UX를 위한 깊은 통찰력. |
주요 의존성 | 아직 보편적이지 않은 최신 브라우저 및 OS 지원이 필요함. | 백엔드 서비스와의 통합. |
패스키 인텔리전스는 데이터를 시간에 따라 수집하고 평가함으로써 한 단계 더 나아갑니다. 이를 통해 더 정교하고 시기적절한 사용자 개입이 가능합니다. 예를 들어, 패스키 인텔리전스 백엔드는 다음을 감지할 수 있습니다.
이러한 데이터 기반 접근 방식은 mediation: 'immediate'
에 대한 브라우저 지원과 무관하므로,
지금 바로 모든 사용자에게 더 지능적인 로그인 흐름을 제공할 수 있습니다.
두 방식의 장점 결합
궁극적으로 이 두 접근 방식은 상호 배타적인 것이 아니라 보완적입니다. 이상적인 솔루션은 이들을 결합하는 것입니다.
mediation: 'immediate'
를 신호 중 하나로
사용하여 빠르고 초기적인 확인을 수행할 수 있습니다.mediation: 'immediate'
의 네이티브 속도와
패스키 인텔리전스
백엔드의 깊은 통찰력을 결합함으로써, 가장 원활하고 적응력 있으며 효과적인 로그인 경험을
제공하여 모든 사용자를 비밀번호 없는 미래로 부드럽게 안내할 수 있습니다.
즉시 중재는 로그인 경험을 크게 향상시킵니다. 이는 패스키로의 전환 중에 사용자들이 겪는 일반적인 마찰과 혼란 지점을 제거하는 데 필요한 인텔리전스를 제공합니다.
immediate
중재는 사용자의
인지 부하를 줄여줍니다. 사용자는 더 이상 어떤 인증 방법을 설정했는지 기억하거나 복잡한
옵션 목록에서 선택할 필요가 없습니다. 로그인 프로세스가 더 간단하고 직관적으로 변합니다.mediation: 'immediate'
는
로컬 자격 증명만 찾기 때문에 이 혼란스러운 상태를 완전히 피할 수 있습니다. 사용자가
흐름을 중단하는 대신, 애플리케이션은 다른 방법으로 자연스럽게 대체하라는 명확한
신호(NotAllowedError
)를 받아 더 원활한 여정을 제공합니다.즉시 중재는 패스키 전환 기간의 분열된 로그인 경험을 해결하는 새로운 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