feat: 앱 네이티브 SDK 소셜 로그인 기능 구현 (구글/카카오)#153
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No description provided. |
Walkthrough앱과 웹 사이에 WebBridge 메시지 계약을 추가하고, Kakao/Google 네이티브 SDK로 로그인하여 백엔드에서 JWT를 교환·저장한 뒤 WebView에 쿠키를 동기화하고 웹에서 결과를 처리하는 전체 흐름을 구현합니다. Changes네이티브 소셜 로그인 통합 (WebBridge 기반)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
apps/app/app/_layout.tsx (1)
6-15: 💤 Low valueSDK 초기화 실패에 대한 에러 핸들링을 추가하는 것을 고려해주세요.
현재 SDK 초기화가 실패하더라도 에러가 무시됩니다. 초기화 실패 시 사용자에게 명확한 피드백을 제공하거나 로깅하는 것이 좋습니다.
에러 핸들링 추가 예시
// 카카오 네이티브 앱 키로 SDK 초기화 (앱 실행 시 1회) -initializeKakaoSDK('326734abdf8de5c7e090a2fc72e1dce6'); +try { + initializeKakaoSDK('326734abdf8de5c7e090a2fc72e1dce6'); +} catch (error) { + console.error('Kakao SDK 초기화 실패:', error); +} // Google Sign-In 설정 -GoogleSignin.configure({ - iosClientId: '978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785.apps.googleusercontent.com', - webClientId: '978975594396-kgl5nei9occteirhlsk9mep9r65t83bn.apps.googleusercontent.com', -}); +try { + GoogleSignin.configure({ + iosClientId: '978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785.apps.googleusercontent.com', + webClientId: '978975594396-kgl5nei9occteirhlsk9mep9r65t83bn.apps.googleusercontent.com', + }); +} catch (error) { + console.error('Google Sign-In 설정 실패:', error); +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/app/app/_layout.tsx` around lines 6 - 15, Wrap the SDK initialization calls in error handling: call initializeKakaoSDK(...) and GoogleSignin.configure(...) inside try/catch blocks (or a single try/catch) and on failure log the error (e.g., console.error or your app logger) and surface user feedback (e.g., Alert.alert or a toast) so failures aren't silently ignored; update the initialization location that currently calls initializeKakaoSDK and GoogleSignin.configure to catch exceptions and handle them accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/app/apis/postSocialLogin.ts`:
- Around line 7-10: Replace the locally redefined PostSocialLoginResponseT with
the shared type from `@piki/core`: import type { SocialLoginSuccessPayloadT } from
'`@piki/core`' and change the postSocialLogin function return type to
Promise<SocialLoginSuccessPayloadT>; remove the duplicate type declaration for
PostSocialLoginResponseT so only the imported SocialLoginSuccessPayloadT is used
across the file (update any references to PostSocialLoginResponseT accordingly).
In `@apps/app/app.json`:
- Around line 13-19: The iOS and Android bundle identifiers are inconsistent:
the iOS "bundleIdentifier" is "day.no30s.piki" while the Android "package" is
"com.piki.app"; confirm intended canonical identifier and update the Android
"package" or the iOS "bundleIdentifier" so both use the same reverse-domain
string (e.g., change "package" to "day.no30s.piki" or change "bundleIdentifier"
to match "com.piki.app"), and ensure any other config or native manifests use
the same identifier (search for "bundleIdentifier" and "package" to apply the
change).
- Around line 38-49: Replace the hardcoded keys by loading them from
environment/EAS secrets: remove the literal strings assigned to nativeAppKey and
iosUrlScheme in app.json and reference environment variables instead (e.g., via
expo config or app.config.js that reads process.env), then store the real values
as EAS secrets and map them in eas.json (KAKAO_NATIVE_APP_KEY,
GOOGLE_IOS_URL_SCHEME). Update the config that sets nativeAppKey and
iosUrlScheme to read process.env.KAKAO_NATIVE_APP_KEY and
process.env.GOOGLE_IOS_URL_SCHEME so the code uses the secrets at build/runtime
instead of the hardcoded values.
In `@apps/app/app/_layout.tsx`:
- Around line 6-15: The SDK keys are hardcoded in initializeKakaoSDK(...) and
GoogleSignin.configure(...); change these calls to read values from
environment/config (e.g., Expo app.json extra or a Constants module) instead of
literals: retrieve kakaoAppKey, googleIosClientId and googleWebClientId from
process.env or Constants.expoConfig.extra and pass those variables into
initializeKakaoSDK and GoogleSignin.configure so the secrets are not embedded in
the source and align with app.json extra.
In `@apps/app/app/index.tsx`:
- Line 48: The JSX currently passes source={isSynced ? { uri:
process.env.EXPO_PUBLIC_WEB_URL ?? 'http://localhost:3000' } : undefined}, which
violates the no-undefined rule; change it to use a conditional spread so the
source prop is only provided when isSynced is true (e.g. spread an object when
isSynced, otherwise spread nothing). Update the JSX around the source prop
(referencing the source prop, the isSynced variable, and
process.env.EXPO_PUBLIC_WEB_URL) to remove the undefined literal and
conditionally supply the prop via spread.
In `@apps/web/src/hooks/useNativeLoginResult.ts`:
- Line 23: The empty catch block in useNativeLoginResult (inside the try/catch
in the useNativeLoginResult hook) should include a brief explanatory comment
stating why errors are intentionally ignored (e.g., non-fatal race condition,
best-effort behavior, or fallback handled elsewhere); update the catch {} to
catch (err) { /* reason: ... */ } so the intent is clear and future maintainers
know this is deliberate rather than accidental.
- Around line 11-22: The handler for MessageEvent currently parses event.data
and accesses message.payload directly, risking saving "undefined" tokens; update
the handler to validate the parsed object with isWebBridgeMessageT (from
`@piki/core`) and confirm message.type ===
WEBBRIDGE_MESSAGE_TYPE.SOCIAL_LOGIN_SUCCESS and that payload.accessToken and
payload.refreshToken are present before calling setCookie('access_token', ...)
and setCookie('refresh_token', ...); if validation fails, treat it like
SOCIAL_LOGIN_ERROR (router.replace('/login')) or ignore the event to avoid
storing invalid tokens.
---
Nitpick comments:
In `@apps/app/app/_layout.tsx`:
- Around line 6-15: Wrap the SDK initialization calls in error handling: call
initializeKakaoSDK(...) and GoogleSignin.configure(...) inside try/catch blocks
(or a single try/catch) and on failure log the error (e.g., console.error or
your app logger) and surface user feedback (e.g., Alert.alert or a toast) so
failures aren't silently ignored; update the initialization location that
currently calls initializeKakaoSDK and GoogleSignin.configure to catch
exceptions and handle them accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bb12f968-0249-4619-a91a-40f7627354c1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
apps/app/apis/postSocialLogin.tsapps/app/app.jsonapps/app/app/_layout.tsxapps/app/app/index.tsxapps/app/eas.jsonapps/app/hooks/useSocialLogin.tsapps/app/hooks/useWebviewCookieSync.tsapps/app/metro.config.jsapps/app/package.jsonapps/app/utils/tokenStorage.tsapps/web/next.config.jsapps/web/src/app/login/_components/LoginButtons.tsxapps/web/src/hooks/useNativeLoginResult.tspackages/core/src/consts/webBridge.tspackages/core/src/index.tspackages/core/src/types/login.tspackages/core/src/types/webBridge.ts
| [ | ||
| "@react-native-kakao/core", | ||
| { | ||
| "nativeAppKey": "326734abdf8de5c7e090a2fc72e1dce6" | ||
| } | ||
| ], | ||
| [ | ||
| "@react-native-google-signin/google-signin", | ||
| { | ||
| "iosUrlScheme": "com.googleusercontent.apps.978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785" | ||
| } | ||
| ], |
There was a problem hiding this comment.
하드코딩된 API 키를 환경 변수 또는 EAS Secret으로 분리해주세요.
nativeAppKey(Line 41)와 iosUrlScheme(Line 47)가 하드코딩되어 있어 보안 위험이 있습니다. 이러한 값들은 Git 저장소에 노출되며, 공개 저장소일 경우 악용될 수 있습니다.
EAS Secret을 사용하거나 환경 변수로 주입하는 방식으로 변경해주세요.
🔐 EAS Secret을 사용한 수정 제안
eas.json에 secret 설정:
{
"build": {
"development": {
"env": {
"KAKAO_NATIVE_APP_KEY": "eas-secret:kakao-app-key",
"GOOGLE_IOS_URL_SCHEME": "eas-secret:google-ios-url-scheme"
}
}
}
}app.json에서 환경 변수 참조:
[
"`@react-native-kakao/core`",
{
- "nativeAppKey": "326734abdf8de5c7e090a2fc72e1dce6"
+ "nativeAppKey": process.env.KAKAO_NATIVE_APP_KEY
}
],
[
"`@react-native-google-signin/google-signin`",
{
- "iosUrlScheme": "com.googleusercontent.apps.978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785"
+ "iosUrlScheme": process.env.GOOGLE_IOS_URL_SCHEME
}
]Secret 등록:
eas secret:create --scope project --name kakao-app-key --value YOUR_KEY
eas secret:create --scope project --name google-ios-url-scheme --value YOUR_SCHEME🧰 Tools
🪛 Betterleaks (1.3.1)
[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/app/app.json` around lines 38 - 49, Replace the hardcoded keys by
loading them from environment/EAS secrets: remove the literal strings assigned
to nativeAppKey and iosUrlScheme in app.json and reference environment variables
instead (e.g., via expo config or app.config.js that reads process.env), then
store the real values as EAS secrets and map them in eas.json
(KAKAO_NATIVE_APP_KEY, GOOGLE_IOS_URL_SCHEME). Update the config that sets
nativeAppKey and iosUrlScheme to read process.env.KAKAO_NATIVE_APP_KEY and
process.env.GOOGLE_IOS_URL_SCHEME so the code uses the secrets at build/runtime
instead of the hardcoded values.
# Conflicts: # apps/app/app.json # apps/app/app/_layout.tsx # apps/app/app/index.tsx # apps/app/eas.json # apps/app/metro.config.js # apps/app/package.json # apps/web/next.config.js # packages/core/src/consts/webBridge.ts # packages/core/src/index.ts # packages/core/src/types/webBridge.ts # pnpm-lock.yaml
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/app/apis/postSocialLogin.ts (1)
23-27:⚠️ Potential issue | 🟠 Major | ⚡ Quick win성공 응답의 토큰 payload를 검증하지 않아
undefined가 전파될 수 있습니다.현재는
data.data를 그대로 반환하므로 응답 구조가 어긋나면 이후 저장/동기화 단계에서 잘못된 인증 상태를 만들 수 있습니다.수정 제안
const data = await response.json(); if (!response.ok) throw new Error(data.detail ?? '로그인에 실패했습니다.'); - return data.data; + const payload = data?.data; + if (!payload?.accessToken || !payload?.refreshToken) { + throw new Error('로그인 응답 형식이 올바르지 않습니다.'); + } + + return payload; };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/app/apis/postSocialLogin.ts` around lines 23 - 27, The function postSocialLogin returns data.data without validating the token payload, which can let undefined propagate; update postSocialLogin to validate the response shape after parsing response.json() by checking that data.data exists and contains required fields (e.g., accessToken, refreshToken, and any expiry/userId fields your app expects), and throw a descriptive Error if those properties are missing or malformed so callers never receive an undefined token object; reference the response, data, and the current return data.data locations when making this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/app/apis/postSocialLogin.ts`:
- Around line 12-13: The code builds the social-login URL using
process.env.EXPO_PUBLIC_API_URL without validating it, causing immediate
failures when the env var is empty; update the logic in postSocialLogin (where
`${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}` is
constructed) to explicitly validate that process.env.EXPO_PUBLIC_API_URL is set
and non-empty before making the fetch—if missing, throw a clear error (or return
a rejected Promise) with a descriptive message like "EXPO_PUBLIC_API_URL is not
configured" so the failure is surfaced early and no network request is
attempted.
In `@apps/app/eas.json`:
- Around line 26-27: The production profile in eas.json is missing required
environment variables (EXPO_PUBLIC_API_URL, EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY,
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID, EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID) which are
used by the SDK init in apps/app/app/_layout.tsx and the login call in
apps/app/apis/postSocialLogin.ts; fix by adding those four keys with the same
values as your other profiles into the "production" object (or move them into a
common/shared profile that all three build profiles inherit from) so production
builds receive non-empty values for social login.
---
Outside diff comments:
In `@apps/app/apis/postSocialLogin.ts`:
- Around line 23-27: The function postSocialLogin returns data.data without
validating the token payload, which can let undefined propagate; update
postSocialLogin to validate the response shape after parsing response.json() by
checking that data.data exists and contains required fields (e.g., accessToken,
refreshToken, and any expiry/userId fields your app expects), and throw a
descriptive Error if those properties are missing or malformed so callers never
receive an undefined token object; reference the response, data, and the current
return data.data locations when making this change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 55856c19-0e93-4f69-a16c-21ad1e1757d7
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
apps/app/apis/postSocialLogin.tsapps/app/app.jsonapps/app/app/_layout.tsxapps/app/app/index.tsxapps/app/eas.jsonapps/app/metro.config.jsapps/app/package.jsonapps/web/next.config.jsapps/web/src/hooks/useNativeLoginResult.tspackages/core/src/consts/webBridge.tspackages/core/src/index.tspackages/core/src/types/webBridge.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/core/src/index.ts
- apps/app/package.json
- packages/core/src/consts/webBridge.ts
- packages/core/src/types/webBridge.ts
- apps/app/app/_layout.tsx
- apps/web/next.config.js
- apps/app/metro.config.js
- apps/app/app/index.tsx
| `${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}`, | ||
| { |
There was a problem hiding this comment.
API base URL 미설정 시 로그인 요청이 즉시 깨집니다.
환경 변수가 비어 있으면 잘못된 URL로 요청되어 소셜 로그인 경로 전체가 실패합니다. 요청 전에 명시적으로 검증해 설정 오류를 조기에 드러내는 게 안전합니다.
수정 제안
export const postSocialLogin = async (
provider: SocialProviderT,
body: PostSocialLoginRequestT
): Promise<SocialLoginSuccessPayloadT> => {
+ const apiBaseUrl = process.env.EXPO_PUBLIC_API_URL;
+ if (!apiBaseUrl) {
+ throw new Error('EXPO_PUBLIC_API_URL이 설정되지 않았습니다.');
+ }
+
const response = await fetch(
- `${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}`,
+ `${apiBaseUrl}/api/v1/auth/login/${provider}`,
{
method: 'POST',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}`, | |
| { | |
| export const postSocialLogin = async ( | |
| provider: SocialProviderT, | |
| body: PostSocialLoginRequestT | |
| ): Promise<SocialLoginSuccessPayloadT> => { | |
| const apiBaseUrl = process.env.EXPO_PUBLIC_API_URL; | |
| if (!apiBaseUrl) { | |
| throw new Error('EXPO_PUBLIC_API_URL이 설정되지 않았습니다.'); | |
| } | |
| const response = await fetch( | |
| `${apiBaseUrl}/api/v1/auth/login/${provider}`, | |
| { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(body), | |
| } | |
| ); | |
| if (!response.ok) { | |
| throw new Error('Failed to login'); | |
| } | |
| return response.json(); | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/app/apis/postSocialLogin.ts` around lines 12 - 13, The code builds the
social-login URL using process.env.EXPO_PUBLIC_API_URL without validating it,
causing immediate failures when the env var is empty; update the logic in
postSocialLogin (where
`${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}` is
constructed) to explicitly validate that process.env.EXPO_PUBLIC_API_URL is set
and non-empty before making the fetch—if missing, throw a clear error (or return
a rejected Promise) with a descriptive message like "EXPO_PUBLIC_API_URL is not
configured" so the failure is surfaced early and no network request is
attempted.
| "production": { | ||
| "autoIncrement": true |
There was a problem hiding this comment.
프로덕션 프로필에도 로그인 필수 env를 넣어 주세요.
Line 26의 production에는 EXPO_PUBLIC_API_URL,
EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY, EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID,
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID가 빠져 있습니다. 이 값들은
apps/app/app/_layout.tsx:1-13의 SDK 초기화와
apps/app/apis/postSocialLogin.ts:3-27의 로그인 API 호출에 직접 쓰이므로,
현재 설정대로면 프로덕션 빌드에서 소셜 로그인이 빈 값/undefined로 깨집니다.
production.env를 추가하거나 공통 프로필로 승격해서 세 프로필이 같은 값을
상속받도록 맞춰 주세요.
수정 예시
"production": {
+ "env": {
+ "EXPO_PUBLIC_API_URL": "https://api.depromeet18team3.cloud",
+ "EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY": "326734abdf8de5c7e090a2fc72e1dce6",
+ "EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID": "978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785.apps.googleusercontent.com",
+ "EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID": "978975594396-kgl5nei9occteirhlsk9mep9r65t83bn.apps.googleusercontent.com"
+ },
"autoIncrement": true
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "production": { | |
| "autoIncrement": true | |
| "production": { | |
| "env": { | |
| "EXPO_PUBLIC_API_URL": "https://api.depromeet18team3.cloud", | |
| "EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY": "326734abdf8de5c7e090a2fc72e1dce6", | |
| "EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID": "978975594396-mo5b39fe8fqfuukqkf42p63tlqkc4785.apps.googleusercontent.com", | |
| "EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID": "978975594396-kgl5nei9occteirhlsk9mep9r65t83bn.apps.googleusercontent.com" | |
| }, | |
| "autoIncrement": true | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/app/eas.json` around lines 26 - 27, The production profile in eas.json
is missing required environment variables (EXPO_PUBLIC_API_URL,
EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY, EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID,
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID) which are used by the SDK init in
apps/app/app/_layout.tsx and the login call in apps/app/apis/postSocialLogin.ts;
fix by adding those four keys with the same values as your other profiles into
the "production" object (or move them into a common/shared profile that all
three build profiles inherit from) so production builds receive non-empty values
for social login.
작업 요약
작업 세부 내용
@piki/core
REQUEST_SOCIAL_LOGIN,SOCIAL_LOGIN_SUCCESS,SOCIAL_LOGIN_ERRORWebBridge 메시지 타입 추가SocialProviderT, 로그인 관련 payload 타입 정의 (types/login.ts)apps/app
eas.json— development/preview/production 프로파일)app.json—@react-native-kakao/core,@react-native-google-signin/google-signin플러그인 설정_layout.tsx— 앱 시작 시 카카오 SDK 초기화(initializeKakaoSDK), Google Sign-In 설정(GoogleSignin.configure)hooks/useSocialLogin.ts— 네이티브 SDK 로그인 → JWT 발급 → 앱 저장 + 웹 전달utils/tokenStorage.ts—expo-secure-store기반 JWT 저장 (iOS Keychain / Android Keystore)apis/postSocialLogin.ts— 백엔드POST /auth/login/{provider}호출app/index.tsx—REQUEST_SOCIAL_LOGIN메시지 수신 시useSocialLogin실행metro.config.js— pnpm 워크스페이스 심링크 해석 설정 추가app.json— 번들 ID를 기존 팀 빌드와 동일한day.no30s.piki로 통일(기존
com.piki.app은 다른 팀 계정에 등록되어 있어 개발 빌드에 사용 불가)apps/web
LoginButtons.tsx— WebView 환경 감지 시 OAuth 리다이렉트 대신WebBridge.postMessage(REQUEST_SOCIAL_LOGIN)발송hooks/useNativeLoginResult.ts— 앱으로부터SOCIAL_LOGIN_SUCCESS수신 → 쿠키 저장 →/home이동next.config.js— 실기기 테스트용allowedDevOrigins환경변수화 (NEXT_PUBLIC_DEV_ORIGIN)로그인 플로우
웹 로그인 버튼 클릭 (WebView)
→ WebBridge: REQUEST_SOCIAL_LOGIN
→ 앱: 네이티브 SDK 로그인 (카카오앱 / 구글 팝업)
→ 앱: POST /auth/login/{provider} { accessToken }
→ 앱: expo-secure-store에 JWT 저장
→ WebBridge: SOCIAL_LOGIN_SUCCESS { accessToken, refreshToken }
→ 웹: 쿠키 저장 → /home 이동
이슈 및 해결
① pnpm 워크스페이스에서 Metro가 네이티브 모듈을 못 찾는 문제
@react-native-kakao/user모듈을 찾지 못하는 오류 발생metro.config.js에unstable_enableSymlinks: true및nodeModulesPaths명시로 해결② Next.js 실기기 접속 시 JS 번들 차단 문제
192.168.219.120)로 웹 서버에 접근하면 Next.js 16이 cross-origin으로 판단해/_next/webpack-hmr리소스를 차단 → 버튼 클릭 불가next.config.js의allowedDevOrigins에 LAN IP 허용으로 해결 (환경변수로 관리)③ 카카오 SDK 초기화 누락
_layout.tsx에서initializeKakaoSDK(appKey)명시적 호출로 해결④ 구글 accessToken 발급 방식
GoogleSignin.signIn()의idToken을 그대로 전달했으나 백엔드가 거부GoogleSignin.getTokens()로accessToken을 별도 발급하여 전달하는 방식으로 해결실기기 테스트 방법
eas build --profile development --platform ios로 Custom Dev Client 빌드 및 기기 설치pnpm --filter piki-web dev로 웹 서버 실행 (NEXT_PUBLIC_DEV_ORIGIN={LAN IP}설정 필요)apps/app/.env에EXPO_PUBLIC_WEB_URL=http://{LAN IP}:3000,EXPO_PUBLIC_API_URL설정npx expo start --dev-client로 앱 서버 실행 후 기기에서 접속기능 작동 확인 영상
d1ddd7c8b05f4bdcb644ca8250037f20.mov
연관 이슈
closes #132
Summary by CodeRabbit
New Features
Chores
Refactor