패스키

Passkeys

기기에 보관한 개인키로 서버의 챌린지에 서명해 로그인합니다.

···
html
<div class="sd"><div class="sd-head"><strong>PASSKEY</strong><span id="state">live check</span></div><div class="sd-stage"><div class="tile" id="server">challenge</div><div class="arrow" id="arrow">→</div><div class="device"><div class="lock">PRIVATE KEY</div><div id="device-state">unlock</div></div><div class="tile good" id="verify">verify</div></div><div class="sd-foot"><span id="caption">checking boundary</span><span>tap to step</span></div></div>
css
.sd{box-sizing:border-box;width:min(94vw,700px);height:min(86vh,318px);padding:clamp(9px,2.3vmin,18px);border:1px solid var(--line);border-radius:14px;background:var(--surface);color:var(--fg);display:flex;flex-direction:column;gap:clamp(6px,1.8vmin,12px);font:600 clamp(12px,2.6vmin,16px)/1.25 var(--font-sans, sans-serif)}.sd *{box-sizing:border-box}.sd-head,.sd-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:1.25em}.sd-head strong{color:var(--accent);letter-spacing:.06em}.sd-head span,.sd-foot{color:var(--muted)}.sd-foot{font-size:clamp(12px,2.4vmin,14px)}.sd-stage{position:relative;flex:1;min-height:0;display:flex;align-items:center;justify-content:center;gap:clamp(6px,2vmin,18px);overflow:hidden}.sd .mono{font-family:ui-monospace,monospace}.sd .tile{border:1px solid var(--line);border-radius:8px;background:var(--bg);padding:clamp(5px,1.5vmin,10px);text-align:center}.sd .good{color:var(--accent);border-color:var(--accent)}.sd .bad{color:var(--accent-3);border-color:var(--accent-3)}.sd .arrow{color:var(--muted);font-size:clamp(15px,4vmin,28px)}.sd .active{background:color-mix(in srgb,var(--accent) 16%,var(--surface));border-color:var(--accent)}.sd .blocked{background:color-mix(in srgb,var(--accent-3) 13%,var(--surface));border-color:var(--accent-3)}.device{border:2px solid var(--accent);border-radius:12px;padding:clamp(6px,2vmin,13px);text-align:center;min-width:30%;background:color-mix(in srgb,var(--accent) 10%,var(--surface))}.lock{font:700 clamp(12px,2.4vmin,13px) ui-monospace,monospace;color:var(--accent)}.device #device-state{margin-top:5px}.sd-stage>.tile{max-width:24%;overflow-wrap:anywhere}
js
let n=-1;function advance(){n=(n+1)%3;document.getElementById('server').textContent=['challenge','challenge','public key'][n];document.getElementById('device-state').textContent=['unlock','sign','signed'][n];document.getElementById('verify').textContent=['waiting','signature','verified'][n];document.getElementById('verify').classList.toggle('active',n===2);document.getElementById('state').textContent=['request','local signing','server check'][n];document.getElementById('caption').textContent=['server sends random challenge','device signs without sharing key','server checks with public key'][n]}advance();setInterval(advance,750);
document.querySelector('.sd').addEventListener('pointerdown',advance);

패스키는 공개키 기반 로그인 자격 증명입니다. 서버에는 공개키가 저장되고, 개인키는 사용자의 기기나 자격 증명 관리자에 남습니다. 로그인 때 기기 잠금 해제 후 서버가 준 챌린지에 서명합니다.

데모는 챌린지·서명·검증 순서를 보여줍니다. 서비스는 사용자의 기기 교체와 계정 복구 흐름도 설계해야 하며, 서버가 비밀키를 직접 받지 않는다는 점이 핵심입니다.

언제 쓰나

비밀번호 의존도를 낮추고 피싱에 강한 로그인을 제공할 때 도입합니다.

페이지로 열기 ↗