Skip to content

Auth Flow

l2juhan edited this page May 12, 2026 · 4 revisions

인증 ν”Œλ‘œμš° (Auth Flow)

μ‚¬μš©μžκ°€ 앱에 μ ‘μ†ν•˜μ—¬ 둜그인/νšŒμ›κ°€μž…ν•˜λŠ” 전체 과정을 μ„€λͺ…ν•©λ‹ˆλ‹€.


1. κ°œμš”

ν•­λͺ© λ‚΄μš©
인증 방식 카카였 둜그인 (OAuth 2.0)
토큰 관리 accessToken (30λΆ„) + refreshToken (14일, μΏ ν‚€)
μƒνƒœ 관리 Zustand + AsyncStorage

2. μ•± μ‹œμž‘ ν”Œλ‘œμš°

μ‚¬μš©μžκ°€ 앱을 μ‹€ν–‰ν–ˆμ„ λ•Œμ˜ λΆ„κΈ° λ‘œμ§μž…λ‹ˆλ‹€.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         μ•± μ‹œμž‘ ν”Œλ‘œμš°                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  [μ•± μ‹œμž‘]                                                      β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  Zustand persist β†’ AsyncStorageμ—μ„œ μƒνƒœ 볡원                    β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  accessToken 있음?                                               β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ βœ… 있음                                                β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β–Ό                                                  β”‚
β”‚      β”‚   userType에 따라 메인 ν™”λ©΄ λΆ„κΈ°                          β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β”œβ”€β†’ WORKER β†’ [WorkerHome]                         β”‚
β”‚      β”‚       └─→ EMPLOYER β†’ [EmployerHome]                     β”‚
β”‚      β”‚               β”‚                                          β”‚
β”‚      β”‚               └─→ 401 λ°œμƒ μ‹œ β†’ refresh μ‹œλ„             β”‚
β”‚      β”‚                       β”‚                                  β”‚
β”‚      β”‚                       β”œβ”€β†’ 성곡 β†’ μƒˆ 토큰 μ €μž₯ β†’ 계속 μ‚¬μš© β”‚
β”‚      β”‚                       └─→ μ‹€νŒ¨ β†’ [둜그인 ν™”λ©΄]           β”‚
β”‚      β”‚                                                          β”‚
β”‚      └─→ ❌ μ—†μŒ                                                β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          isOnboardingCompleted 확인                              β”‚
β”‚              β”‚                                                  β”‚
β”‚              β”œβ”€β†’ true  β†’ [둜그인 ν™”λ©΄] (μ˜¨λ³΄λ”© μŠ€ν‚΅)             β”‚
β”‚              β”‚                                                  β”‚
β”‚              └─→ false β†’ [μ˜¨λ³΄λ”© ν™”λ©΄]                          β”‚
β”‚                              β”‚                                  β”‚
β”‚                              β–Ό                                  β”‚
β”‚                         "μ‹œμž‘ν•˜κΈ°" λ²„νŠΌ                          β”‚
β”‚                              β”‚                                  β”‚
β”‚                              β–Ό                                  β”‚
β”‚                         [둜그인 ν™”λ©΄]                            β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

μ‹œλ‚˜λ¦¬μ˜€λ³„ λ™μž‘

μ‹œλ‚˜λ¦¬μ˜€ μ˜¨λ³΄λ”© 둜그인 이동 ν™”λ©΄
μ•± 졜초 μ„€μΉ˜ ν›„ 첫 μ‹€ν–‰ βœ… ν‘œμ‹œ ν•„μš” μ˜¨λ³΄λ”© β†’ 둜그인
νšŒμ›κ°€μž… μ™„λ£Œ ν›„ μ•± μž¬μ‹œμž‘ ❌ μŠ€ν‚΅ μžλ™ 메인 ν™”λ©΄
14일 ν›„ 토큰 만료 μ‹œ ❌ μŠ€ν‚΅ ν•„μš” 둜그인 ν™”λ©΄
λ‘œκ·Έμ•„μ›ƒ ν›„ ❌ μŠ€ν‚΅ ν•„μš” 둜그인 ν™”λ©΄
μ•± μ‚­μ œ ν›„ μž¬μ„€μΉ˜ βœ… ν‘œμ‹œ ν•„μš” μ˜¨λ³΄λ”© β†’ 둜그인

3. 카카였 둜그인 ν”Œλ‘œμš°

카카였 둜그인 λ²„νŠΌ 클릭 ν›„μ˜ 처리 κ³Όμ •μž…λ‹ˆλ‹€.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      카카였 둜그인 ν”Œλ‘œμš°                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  [카카였 둜그인 λ²„νŠΌ 클릭]                                        β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  카카였 SDK 호좜 β†’ kakaoAccessToken νšλ“                         β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  λ°±μ—”λ“œ POST /api/auth/kakao/login { kakaoAccessToken }          β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ 200 OK + status="LOGGED_IN" (κΈ°μ‘΄ νšŒμ›)                 β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β–Ό                                                  β”‚
β”‚      β”‚   accessToken μ €μž₯ (AsyncStorage)                        β”‚
β”‚      β”‚   refreshToken μ €μž₯ (μΏ ν‚€)                                β”‚
β”‚      β”‚   userInfo μ €μž₯ (userId, name, userType)                 β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β–Ό                                                  β”‚
β”‚      β”‚   userType에 따라 메인 ν™”λ©΄ λΆ„κΈ°                          β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β”œβ”€β†’ WORKER β†’ [WorkerHome]                         β”‚
β”‚      β”‚       └─→ EMPLOYER β†’ [EmployerHome]                     β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ 200 OK + status="WITHDRAWN_PENDING" (νƒˆν‡΄ 보λ₯˜ 계정)    β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β–Ό                                                  β”‚
β”‚      β”‚   [WithdrawnAccountSheet] (Β§3-1 μ°Έκ³ )                    β”‚
β”‚      β”‚                                                          β”‚
β”‚      └─→ 404 USER_NOT_FOUND (μ‹ κ·œ νšŒμ›)                          β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          signUpStore.mode = "register"                          β”‚
β”‚          kakaoAccessToken을 signUpStore에 μž„μ‹œ μ €μž₯              β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          [νšŒμ›κ°€μž… ν™”λ©΄] (STEP 1)                                β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’‘ 카카였 둜그인 응닡은 2026-05 이후 KakaoLoginResult ꡬ쑰둜 변경됐닀. status ν•„λ“œ(LOGGED_IN / WITHDRAWN_PENDING)둜 λΆ„κΈ°ν•˜λ©°, μ‹ κ·œ μ‚¬μš©μžλŠ” 기쑴처럼 404둜 λ–¨μ–΄μ§„λ‹€.


3-1. νƒˆν‡΄ 계정 볡ꡬ/μž¬κ°€μž… ν”Œλ‘œμš° (2026-05 μΆ”κ°€)

νšŒμ› νƒˆν‡΄λŠ” μ¦‰μ‹œ μ‚­μ œκ°€ μ•„λ‹ˆλΌ soft delete + 30일 유예 방식이닀. 유예 κΈ°κ°„ μ•ˆμ— 같은 카카였 κ³„μ •μœΌλ‘œ λ‹€μ‹œ λ‘œκ·ΈμΈμ„ μ‹œλ„ν•˜λ©΄ μ‚¬μš©μžμ—κ²Œ "볡ꡬ" λ˜λŠ” "μƒˆ κ³„μ •μœΌλ‘œ κ°€μž…" 두 κ°€μ§€ 선택을 μ•ˆλ‚΄ν•œλ‹€.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  νƒˆν‡΄ 보λ₯˜ 계정 처리 ν”Œλ‘œμš°                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  [/kakao/login β†’ status="WITHDRAWN_PENDING"]                    β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”‚   응닡에 withdrawnAccount 포함:                          β”‚
β”‚      β”‚     β€’ name                                               β”‚
β”‚      β”‚     β€’ userType ("WORKER" | "EMPLOYER")                   β”‚
β”‚      β”‚     β€’ withdrawnAt (νƒˆν‡΄ μ‹œκ°)                            β”‚
β”‚      β”‚     β€’ profileImageUrl                                    β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  [WithdrawnAccountSheet] ν‘œμ‹œ                                    β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ "κΈ°μ‘΄ 계정 볡ꡬ"                                       β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β–Ό                                                  β”‚
β”‚      β”‚   POST /api/auth/kakao/restore                          β”‚
β”‚      β”‚       { kakaoAccessToken }                              β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       β”œβ”€β†’ 200 OK                                         β”‚
β”‚      β”‚       β”‚       └─→ User.deletedAt = null                  β”‚
β”‚      β”‚       β”‚           accessToken/refreshToken λ°œκΈ‰          β”‚
β”‚      β”‚       β”‚           β†’ μžλ™ 둜그인 β†’ 메인 ν™”λ©΄              β”‚
β”‚      β”‚       β”‚                                                  β”‚
β”‚      β”‚       └─→ μ‹€νŒ¨ β†’ μ—λŸ¬ μ•ˆλ‚΄ β†’ μ‹œνŠΈ λ‹«κΈ°                   β”‚
β”‚      β”‚                                                          β”‚
β”‚      └─→ "μƒˆ κ³„μ •μœΌλ‘œ κ°€μž…"                                     β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          signUpStore.mode = "purge-and-register"                β”‚
β”‚          signUpStore.kakaoAccessToken = (ν˜„μž¬ 토큰)              β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          [νšŒμ›κ°€μž… ν™”λ©΄] (STEP 1λΆ€ν„° μž¬μž…λ ₯)                     β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          [STEP 4] μ™„λ£Œ μ‹œμ μ— λΆ„κΈ°:                              β”‚
β”‚          POST /api/auth/kakao/purge-and-register                β”‚
β”‚              β”‚   (κΈ°μ‘΄ νƒˆν‡΄ 계정 + μ‚°ν•˜ 데이터 영ꡬ μ‚­μ œ ν›„      β”‚
β”‚              β”‚    μ‹ κ·œ μ‚¬μš©μžλ‘œ κ°€μž…, νŠΈλžœμž­μ…˜μœΌλ‘œ μ›μžμ„± 보μž₯)   β”‚
β”‚              β–Ό                                                  β”‚
β”‚          μƒˆ accessToken/refreshToken λ°œκΈ‰ β†’ 둜그인 β†’ 메인       β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

볡ꡬ API

μ—”λ“œν¬μΈνŠΈ: POST /api/auth/kakao/restore

Request Body:

{ "kakaoAccessToken": "string" }

Response Body (성곡 μ‹œ): LoginResponse와 동일 ꡬ쑰(accessToken/refreshToken/userId/name/userType)

μƒνƒœ 의미
200 OK 볡ꡬ 성곡 β€” User.deletedAt이 null둜 볡ꡬ되고 토큰 λ°œκΈ‰
400 USER_NOT_WITHDRAWN νƒˆν‡΄ μƒνƒœκ°€ μ•„λ‹Œ 계정에 호좜
404 USER_NOT_FOUND λ“±λ‘λ˜μ§€ μ•Šμ€ 카카였 계정

⚠️ λ³΅κ΅¬λŠ” νƒˆν‡΄ μ‹œ 보쑴된 UserSettings만 κ·ΈλŒ€λ‘œ μœ μ§€ν•œλ‹€. 사업μž₯/계약/근무기둝은 μžλ™ λ³΅κ΅¬λ˜μ§€ μ•ŠλŠ”λ‹€ (λ‹€λ₯Έ μ‚¬μš©μž 데이터 일관성 보호).

μž¬κ°€μž…(영ꡬ μ‚­μ œ ν›„ μ‹ κ·œ κ°€μž…) API

μ—”λ“œν¬μΈνŠΈ: POST /api/auth/kakao/purge-and-register

Request Body: /api/auth/kakao/register와 동일 (kakaoAccessToken/name/userType/phone/bankName/accountNumber/profileImageUrl)

Response Body (성곡 μ‹œ): LoginResponse와 동일 ꡬ쑰

μƒνƒœ 의미
200 OK κΈ°μ‘΄ νƒˆν‡΄ 계정 hard delete + μ‹ κ·œ κ°€μž… 성곡
400 DUPLICATE_KAKAO_ACCOUNT 정상 μƒνƒœ 계정에 호좜 (νƒˆν‡΄ κ³„μ •μ—λ§Œ μ‚¬μš© κ°€λŠ₯)

λ°±μ—”λ“œλŠ” ν•œ νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œ hard delete β†’ registerλ₯Ό 순차 μ²˜λ¦¬ν•˜λ©°, register μ‹€νŒ¨ μ‹œ hard delete도 ν•¨κ»˜ λ‘€λ°±λ˜μ–΄ 데이터 영ꡬ 손싀을 λ°©μ§€ν•œλ‹€.

ν”„λ‘ νŠΈ κ΅¬ν˜„ λ©”λͺ¨

  • signUpStore의 mode ν•„λ“œ("register" | "purge-and-register")κ°€ STEP 4 μ•ŒλžŒ ν™”λ©΄μ—μ„œ μ–΄λŠ APIλ₯Ό ν˜ΈμΆœν• μ§€ κ²°μ •ν•œλ‹€.
  • SignUpNavigator 마운트 μ‹œμ—λŠ” reset()이 μ•„λ‹Œ resetForm()을 ν˜ΈμΆœν•΄ modeλ₯Ό λ³΄μ‘΄ν•œλ‹€. 폼 ν•„λ“œλ§Œ μ΄ˆκΈ°ν™”ν•˜λ©°, mode/kakaoAccessToken은 호좜자(WelcomeScreen)κ°€ 사전 μ„€μ •ν•œ 값을 μœ μ§€ν•œλ‹€.
  • 일반 μ‹ κ·œ κ°€μž…(404 λΆ„κΈ°)μ—μ„œλ„ setMode("register")λ₯Ό λͺ…μ‹œ ν˜ΈμΆœν•΄ 이전 μ„Έμ…˜μ˜ mode μž”μ—¬λ₯Ό λ°©μ§€ν•œλ‹€.

4. νšŒμ›κ°€μž… ν”Œλ‘œμš°

μ‹ κ·œ μ‚¬μš©μžμ˜ νšŒμ›κ°€μž… 5단계 κ³Όμ •μž…λ‹ˆλ‹€.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       νšŒμ›κ°€μž… ν”Œλ‘œμš°                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  [STEP 1/5] νšŒμ›μœ ν˜• 선택                                        β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ "근둜자" 선택 β†’ userType: "WORKER"                     β”‚
β”‚      └─→ "사μž₯λ‹˜" 선택 β†’ userType: "EMPLOYER"                   β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚  [STEP 2/5] ν”„λ‘œν•„ 사진 (선택)                                   β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ 이미지 선택 β†’ 400x400 λ¦¬μ‚¬μ΄μ¦ˆ β†’ μ••μΆ• β†’ base64 인코딩   β”‚
β”‚      └─→ "λ‚˜μ€‘μ— μ„€μ •ν•˜κΈ°" β†’ μŠ€ν‚΅                               β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚  [STEP 3/5] 기본정보 μž…λ ₯                                        β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”‚   β€’ 이름 (ν•„μˆ˜)                                          β”‚
β”‚      β”‚   β€’ ν•Έλ“œν° 번호 (010-XXXX-XXXX)                          β”‚
β”‚      β”‚   β€’ 은행λͺ… (λͺ¨λ‹¬ 선택) - 근둜자만                         β”‚
β”‚      β”‚   β€’ κ³„μ’Œλ²ˆν˜Έ - 근둜자만                                   β”‚
β”‚      β”‚                                                          β”‚
β”‚              β–Ό                                                  β”‚
β”‚  [STEP 4/5] μ•ŒλžŒ μ„€μ • + νšŒμ›κ°€μž… API 호좜                        β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ "μ•ŒλžŒ ν—ˆμš©" β†’ μ‹œμŠ€ν…œ κΆŒν•œ μš”μ²­ β†’ API 호좜              β”‚
β”‚      └─→ "λ‚˜μ€‘μ— μ„€μ •ν•˜κΈ°" β†’ API 호좜                           β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          λ°±μ—”λ“œ POST /api/auth/kakao/register 호좜               β”‚
β”‚              β”‚                                                  β”‚
β”‚              β”œβ”€β†’ 성곡                                           β”‚
β”‚              β”‚       β”‚                                          β”‚
β”‚              β”‚       β–Ό                                          β”‚
β”‚              β”‚   accessToken μ €μž₯ (AsyncStorage)                β”‚
β”‚              β”‚   userInfo μ €μž₯ (userId, name, userType)         β”‚
β”‚              β”‚       β”‚                                          β”‚
β”‚              β”‚       β–Ό                                          β”‚
β”‚              β”‚   [STEP 5/5] κ°€μž…μ™„λ£Œ ν™”λ©΄                        β”‚
β”‚              β”‚                                                  β”‚
β”‚              └─→ μ‹€νŒ¨ (400 λ“±)                                  β”‚
β”‚                      β”‚                                          β”‚
β”‚                      β–Ό                                          β”‚
β”‚                  μ—λŸ¬ Toast ν‘œμ‹œ                                 β”‚
β”‚                  signUpStore μ΄ˆκΈ°ν™”                              β”‚
β”‚                  [둜그인 ν™”λ©΄]으둜 이동                          β”‚
β”‚                                                                 β”‚
β”‚  [STEP 5/5] κ°€μž…μ™„λ£Œ                                             β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”‚   signUpStore μ΄ˆκΈ°ν™”                                     β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ WORKER β†’ "μ‹œμž‘ν•˜κΈ°" β†’ [WorkerHome]                     β”‚
β”‚      └─→ EMPLOYER β†’ "λ§€μž₯ κ΄€λ¦¬ν•˜λŸ¬ κ°€κΈ°" β†’ [WorkplaceManage]    β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

νšŒμ›κ°€μž… API

μ—”λ“œν¬μΈνŠΈ: POST /api/auth/kakao/register

Request Body:

{
  "kakaoAccessToken": "string",
  "name": "string",
  "userType": "WORKER",
  "phone": "010-1234-5678",
  "bankName": "string",
  "accountNumber": "string",
  "profileImageUrl": "base64 λ¬Έμžμ—΄ λ˜λŠ” 빈 λ¬Έμžμ—΄"
}
ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
kakaoAccessToken string βœ… 카카였 둜그인 토큰
name string βœ… μ‚¬μš©μž 이름
userType string βœ… "WORKER" λ˜λŠ” "EMPLOYER"
phone string βœ… ν•Έλ“œν° 번호 (ν•˜μ΄ν”ˆ 포함)
bankName string ❌ 은행λͺ… (근둜자만 ν•„μˆ˜)
accountNumber string ❌ κ³„μ’Œλ²ˆν˜Έ (근둜자만 ν•„μˆ˜)
profileImageUrl string ❌ base64 μΈμ½”λ”©λœ 이미지

Response Body (성곡 μ‹œ):

{
  "success": true,
  "data": {
    "accessToken": "string",
    "userType": "WORKER",
    "userId": 123,
    "name": "홍길동"
  }
}

5. 토큰 관리

μ €μž₯ μœ„μΉ˜

토큰 μ €μž₯ μœ„μΉ˜ 수λͺ… 관리 방식
accessToken AsyncStorage + Zustand 30λΆ„ ν΄λΌμ΄μ–ΈνŠΈ 직접 관리
refreshToken μΏ ν‚€ (HttpOnly) 14일 μ„œλ²„κ°€ Set-Cookie둜 전솑
kakaoAccessToken signUpStore (μž„μ‹œ) - νšŒμ›κ°€μž… μ™„λ£Œ μ‹œ μ‚­μ œ

토큰 κ°±μ‹  ν”Œλ‘œμš°

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        토큰 κ°±μ‹  ν”Œλ‘œμš°                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  [API μš”μ²­]                                                     β”‚
β”‚      β”‚                                                          β”‚
β”‚      β–Ό                                                          β”‚
β”‚  Authorization: Bearer {accessToken}                            β”‚
β”‚      β”‚                                                          β”‚
β”‚      β”œβ”€β†’ 200 OK β†’ 정상 응닡                                     β”‚
β”‚      β”‚                                                          β”‚
β”‚      └─→ 401 Unauthorized (토큰 만료)                           β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          CookieManager.get(baseURL)둜 μΏ ν‚€ 직접 쑰회              β”‚
β”‚          β†’ Cookie 헀더에 μˆ˜λ™ 첨뢀 (RN은 μžλ™ 전솑 미지원)       β”‚
β”‚              β”‚                                                  β”‚
β”‚              β–Ό                                                  β”‚
β”‚          POST /api/auth/refresh (Cookie 헀더에 refreshToken)     β”‚
β”‚              β”‚                                                  β”‚
β”‚              β”œβ”€β†’ 200 OK                                         β”‚
β”‚              β”‚       β”‚                                          β”‚
β”‚              β”‚       β–Ό                                          β”‚
β”‚              β”‚   μƒˆ accessToken μ €μž₯                            β”‚
β”‚              β”‚   μ›λž˜ API μš”μ²­ μž¬μ‹œλ„                            β”‚
β”‚              β”‚                                                  β”‚
β”‚              └─→ 401/403 (refreshToken도 만료)                  β”‚
β”‚                      β”‚                                          β”‚
β”‚                      β–Ό                                          β”‚
β”‚                  logoutCallback() 호좜                          β”‚
β”‚                  β†’ μ €μž₯된 토큰/μΏ ν‚€ μ‚­μ œ                         β”‚
β”‚                  β†’ [둜그인 ν™”λ©΄]으둜 이동                        β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

React Native μΏ ν‚€ 처리 μ£Όμ˜μ‚¬ν•­ (2026-03-09 μˆ˜μ •, PR #45)

React Native ν™˜κ²½μ€ Axios의 withCredentials: trueλ§ŒμœΌλ‘œλŠ” μΏ ν‚€κ°€ μžλ™ μ „μ†‘λ˜μ§€ μ•ŠλŠ”λ‹€. 이에 따라 κ°±μ‹  μΈν„°μ…‰ν„°μ—μ„œ μΏ ν‚€λ₯Ό μˆ˜λ™μœΌλ‘œ 읽어 헀더에 μ²¨λΆ€ν•˜λŠ” ꡬ쑰λ₯Ό μ‚¬μš©ν•œλ‹€.

이슈 이전 κ΅¬ν˜„ ν˜„μž¬ κ΅¬ν˜„
λ¦¬ν”„λ ˆμ‹œ μš”μ²­ μ‹œ μΏ ν‚€ 전솑 withCredentials: true만 μ‚¬μš© β†’ μΏ ν‚€ 미전솑 CookieManager.get(baseURL)둜 쑰회 ν›„ Cookie 헀더에 μˆ˜λ™ 첨뢀
κ°±μ‹  μ‹€νŒ¨ μ‹œ ν™”λ©΄ 이동 콜백 미등둝 β†’ 빈 UI RootNavigatorμ—μ„œ isNavReady 이후 setLogoutCallback 등둝
λ‘œκ·Έμ•„μ›ƒ API μ‹€νŒ¨ 처리 μ—λŸ¬ Toast ν‘œμ‹œ + κ°‡νž˜ Toast 제거, finally 블둝이 ν™”λ©΄ 이동 보μž₯

πŸ“ ν–₯ν›„ κ³„νš: PR #65(OPEN)μ—μ„œ @react-native-cookies/cookies μ˜μ‘΄μ„± 제거 ν›„ refreshToken을 body둜 μ „μ†‘ν•˜λŠ” λ°©μ‹μœΌλ‘œ μ „ν™˜ μ˜ˆμ •.


6. μƒνƒœ μ €μž₯ ꡬ쑰

Zustand Store

authStore (AsyncStorage persist):

interface AuthState {
  accessToken: string | null;
  userInfo: UserInfo | null;  // { userId, name, userType }
  isLoggedIn: boolean;
  isHydrated: boolean;
}

onboardingStore (AsyncStorage persist):

interface OnboardingState {
  isOnboardingCompleted: boolean;
  isHydrated: boolean;
}

signUpStore (persist μ—†μŒ - μž„μ‹œ μ €μž₯):

type SignUpMode = "register" | "purge-and-register";

interface SignUpState {
  kakaoAccessToken: string | null;
  mode: SignUpMode;                  // νšŒμ›κ°€μž… λΆ„κΈ° (νƒˆν‡΄ 계정 μž¬κ°€μž… 식별)
  userType: "WORKER" | "EMPLOYER" | null;
  profileImageUri: string | null;
  profileImageBase64: string | null;
  name: string;
  phone: string;
  bankName: string;
  accountNumber: string;
}

modeλŠ” STEP 4μ—μ„œ kakaoRegisterWithToken vs kakaoPurgeAndRegisterWithToken 뢄기에 μ‚¬μš©λœλ‹€. resetForm()은 폼 ν•„λ“œλ§Œ, reset()은 전체(mode 포함) μ΄ˆκΈ°ν™”.

데이터 흐름

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        데이터 흐름                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  1. μ•± μ‹œμž‘                                                     β”‚
β”‚     └─→ AsyncStorageμ—μ„œ Zustand둜 μƒνƒœ 볡원 (authStore)         β”‚
β”‚     └─→ AsyncStorageμ—μ„œ Zustand둜 μƒνƒœ 볡원 (onboardingStore)   β”‚
β”‚     └─→ μΏ ν‚€μ—μ„œ refreshToken μžλ™ λ‘œλ“œ                         β”‚
β”‚                                                                 β”‚
β”‚  2. μ•± μ‚¬μš© 쀑                                                  β”‚
β”‚     └─→ Zustand Storeμ—μ„œ 읽기/μ“°κΈ° (λΉ λ₯Έ μ ‘κ·Ό)                 β”‚
β”‚                                                                 β”‚
β”‚  3. μ€‘μš”ν•œ λ³€κ²½ μ‹œ (둜그인/λ‘œκ·Έμ•„μ›ƒ)                             β”‚
β”‚     └─→ AsyncStorage에 μžλ™ 동기화 (persist)                    β”‚
β”‚                                                                 β”‚
β”‚  4. μ•± μ’…λ£Œ                                                     β”‚
β”‚     └─→ Zustand μ΄ˆκΈ°ν™”λ¨ (λ©”λͺ¨λ¦¬)                               β”‚
β”‚     └─→ AsyncStorage, μΏ ν‚€λŠ” μœ μ§€λ¨                             β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

7. ν™”λ©΄ λͺ©λ‘

ν™”λ©΄ μ„€λͺ… κ΄€λ ¨ Issue
μ˜¨λ³΄λ”© (3νŽ˜μ΄μ§€) μ•± μ†Œκ°œ μŠ€μ™€μ΄ν”„ ν™”λ©΄ #1
둜그인 (Welcome) 카카였 둜그인 λ²„νŠΌ #1
νšŒμ›κ°€μž… STEP 1 νšŒμ›μœ ν˜• 선택 #2
νšŒμ›κ°€μž… STEP 2 ν”„λ‘œν•„ 사진 #2
νšŒμ›κ°€μž… STEP 3 기본정보 μž…λ ₯ #2
νšŒμ›κ°€μž… STEP 4 μ•ŒλžŒ μ„€μ • + API 호좜 #2
νšŒμ›κ°€μž… STEP 5 κ°€μž…μ™„λ£Œ #2

8. ν•„μˆ˜ 라이브러리

# λ„€λΉ„κ²Œμ΄μ…˜
npm install @react-navigation/native @react-navigation/native-stack

# 인증/μ €μž₯
npm install @react-native-cookies/cookies
npm install @react-native-async-storage/async-storage
npm install @react-native-seoul/kakao-login
npm install zustand

# 이미지 처리
npm install expo-image-picker
npm install expo-image-manipulator

# μ•Œλ¦Ό
npm install expo-notifications
npm install expo-device

# 기타
npm install react-native-alert-notification

9. API μ—”λ“œν¬μΈνŠΈ μš”μ•½

λ©”μ„œλ“œ μ—”λ“œν¬μΈνŠΈ μ„€λͺ…
POST /api/auth/kakao/login 카카였 둜그인 (status: LOGGED_IN / WITHDRAWN_PENDING λΆ„κΈ°)
POST /api/auth/kakao/register 카카였 νšŒμ›κ°€μž…
POST /api/auth/kakao/restore νƒˆν‡΄ 계정 볡ꡬ (deletedAt=null)
POST /api/auth/kakao/purge-and-register νƒˆν‡΄ 계정 영ꡬ μ‚­μ œ ν›„ μ‹ κ·œ κ°€μž…
POST /api/auth/refresh 토큰 κ°±μ‹ 
POST /api/auth/logout λ‘œκ·Έμ•„μ›ƒ
DELETE /api/auth/withdraw νšŒμ› νƒˆν‡΄ (soft delete + 30일 유예)