“패스키 달면 끝”이 아니라, 사용자가 잃어버리는 것(기기, 계정, 생체)과 서버가 믿는 것(공개키, challenge, origin)을 다시 정리해야 합니다. 이 글은 구현 라이브러리 나열 대신, 비밀번호와의 차이와 WebAuthn에 등장하는 역할만 짚고 넘어갈게요.
사용자가 체감하는 차이
비밀번호는 결국 기억하거나 메모한 공유 비밀이고, 유출·재사용·피싱에 노출됩니다. 패스키는 기기/OS가 보관하는 비대칭 키로, 서버에는 공개키만 남습니다. 도메인에 바인딩되기 때문에 피싱 사이트에서 같은 공격이 잘 먹지 않는다는 이야기가 자주 나오는 이유예요.
다만 복구 UX는 오히려 더 어려워질 수 있어요. “이메일 재설정” 한 방에 끝나던 흐름이, 패스키만으로 가면 다른 기기 등록, 백업 키, 인간 상담 같은 설계가 필요해질 수 있습니다.
WebAuthn에서 꼭 알아둘 세 이름
스펙을 읽을 때 등장하는 Relying Party(RP), 클라이언트(브라우저), Authenticator만 정리돼 있어도 문서가 반은 읽힙니다. RP는 당신의 백엔드와 도메인, 브라우저는 navigator.credentials 쪽 UI와 출처 전달, Authenticator는 플랫폼(TPM)이나 보안 키 쪽입니다.
Next.js App Router를 쓴다면 보통 Route Handler에서 challenge를 세션에 싣고, 검증 후 세션 쿠키를 발급하는 패턴이 많습니다. 서명 검증·credentialId 매핑은 검증된 라이브러리를 쓰는 편이 안전하고, “직접 ASN.1 파싱”은 피하는 게 좋아요.
점진 도입을 추천하는 이유
이미 비밀번호+MFA를 쓰는 서비스라면, 비밀번호와 패스키를 병행한 뒤 로그인 화면에서 패스키를 조금씩 앞으로 당기는 방식이 운영 리스크가 적습니다. 팀에는 “패스키가 비밀번호를 대체할 수 있는지”보다 “어떤 사용자 세그먼트부터 시도할지”를 먼저 정하라고 말하고 싶어요.
정리
패스키는 인증 UX와 보안 아키텍처를 동시에 바꾸는 큰 결정입니다. 이 글은 그 결정을 할 때 필요한 개념 지도만 그렸고, 실제 도입 시에는 제품별 제약(브라우저, 기업 정책, 규제)을 릴리즈 노트 수준까지 따라가야 합니다. 이후에 실제 Route Handler 예제가 필요하면 그때 코드 편으로 이어 볼게요.