For AI agents: fetch the complete documentation index at /llms.txt, the full documentation corpus at /llms-full.txt, the agent skill at /skill.md, or this page as Markdown at /ko/docs/mobile/passkeys.md (or send Accept: text/markdown).
패스키 로그인
브라우저 핸드오프를 통해 세션을 앱으로 되돌려 주는 비밀번호 없는 로그인.
핸드오프 작동 방식
패스키 로그인은 앱에서 시작해 시스템 브라우저에서 완료됩니다. 앱은 WebBrowser.openAuthSessionAsync를 통해 {API URL}/auth?mobile_callback=<deep link>를 열고, 웹 페이지가 어떤 로그인 방법이든 완료하면 GET /api/auth/mobile-handoff를 호출합니다. 그 호출은 세션 쿠키와 state nonce를 담아 <scheme>://auth/callback으로 다시 리디렉션합니다.
매 시도마다 변경 없이 왕복해야 하는 새 nonce가 생성됩니다 — state 매개변수가 일치하지 않으면 stateMismatch로 거부되므로 오래되거나 위조된 콜백이 세션을 주입할 수 없습니다. 반환된 쿠키는 Better Auth Expo 클라이언트가 사용하는 것과 같은 SecureStore 저장소(supastack.auth_cookie)에 병합된 다음 세션 스토어에 알려지고 로그인된 앱이 렌더링됩니다.
사용자가 브라우저 시트를 닫으면 오류가 아니라 조용한 cancelled 결과로 처리되므로, 이 경우 로그인 화면을 그대로 유지하세요.
# apps/mobile/.env.local
EXPO_PUBLIC_APP_SCHEME=supastack
# apps/web/.env.local — server side
AUTH_PASSKEY_ENABLED=true
MOBILE_ALLOWED_ORIGINS=양쪽의 허용 목록을 동일하게 유지하세요
양쪽 모두 콜백 대상을 검증합니다. 앱은 <scheme>://auth와 구성된 프로덕션 오리진만 허용하고, 서버는 EXPO_PUBLIC_APP_SCHEME과 MOBILE_ALLOWED_ORIGINS로 만든 동일한 목록을 검사합니다. 자격 증명, 알 수 없는 스킴, 비슷해 보이는 접미사를 담은 콜백은 쿠키가 이동하기 전에 거부됩니다.
프로덕션에서는 MOBILE_ALLOWED_ORIGINS가 필수이며 로컬이 아닌 정확한 HTTPS 오리진을 나열해야 합니다 — 와일드카드는 허용되지 않습니다. 앱은 번들로 배포되는 반면 서버는 요청마다 환경을 읽으므로, 스킴이나 오리진 변경에는 새 앱 빌드와 서버 배포가 모두 필요합니다. 한쪽만 바꾸면 핸드오프가 닫혀서 실패합니다.
다른 비밀번호 없는 로그인 방법
같은 로그인 화면에서 이메일 일회용 코드(requestEmailOtp 다음 verifyEmailOtp)와 callbackURL을 사용하는 signIn.social을 통한 Apple 또는 Google 소셜 로그인을 제공합니다. 패스키는 서버에 AUTH_PASSKEY_ENABLED=true가 설정되면 나타납니다. 계정의 패스키와 2단계 인증 설정은 여전히 웹 앱의 설정 → 보안에 있습니다.
검증 및 문제 해결
대상 빌드에서 콜드 스타트 콜백, 실행 중인 앱으로의 복귀, 취소된 브라우저 시트, 만료된 세션을 각각 실행해 보세요. 타입이 지정된 실패 — passkeyUnavailable, browserFailed, untrustedCallback, missingCookie, malformedCookie, cookieStoreFailed — 는 각각 서로 다른 고장을 설명합니다. stateMismatch는 nonce가 왕복하지 못했고 시도가 올바르게 거부되었음을 의미합니다.
모든 핸드오프가 거부되면 배포된 빌드의 EXPO_PUBLIC_APP_SCHEME을 서버의 스킴 및 MOBILE_ALLOWED_ORIGINS와 비교하세요 — 한쪽만 다시 배포되면 이 쌍이 어긋납니다.