> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# 패스키 로그인

브라우저 핸드오프를 통해 세션을 앱으로 되돌려 주는 비밀번호 없는 로그인.

## 핸드오프 작동 방식

패스키 로그인은 앱에서 시작해 시스템 브라우저에서 완료됩니다. 앱은 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와 비교하세요 — 한쪽만 다시 배포되면 이 쌍이 어긋납니다.


## 다음

[모바일 API](https://supastack.dev/ko/docs/mobile/api.md)
