From 7f18d18a116d4d69578169c08bea1d0f9bb4694c Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sun, 12 Jul 2026 11:02:51 +0900 Subject: [PATCH] =?UTF-8?q?feat(auth):=20=EC=95=B1(=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=ED=8B=B0=EB=B8=8C)=20=EA=B5=AC=EA=B8=80=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=E2=80=94=20@capgo/capacitor-social-login?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 웹은 기존 GIS 유지, Capacitor 네이티브(APK)는 네이티브 구글 로그인 사용 (웹뷰에서 GIS 팝업/FedCM 미동작 대응) - 받은 ID 토큰은 기존과 동일하게 백엔드 /api/auth/google 로 검증 - src/lib/googleAuth.ts + LoginPage 네이티브/웹 분기 Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/lib/googleAuth.ts | 35 +++++++++++++++++++++++++++++++++++ src/pages/LoginPage.vue | 38 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/lib/googleAuth.ts diff --git a/package-lock.json b/package-lock.json index 00d8c4d..6853b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@capacitor/app": "^8.0.0", "@capacitor/core": "^8.3.4", "@capacitor/geolocation": "^8.2.0", + "@capgo/capacitor-social-login": "^8.3.36", "@quasar/extras": "^1.16.12", "@stomp/stompjs": "^7.3.0", "pinia": "^2.3.0", @@ -187,6 +188,18 @@ "integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==", "license": "ISC" }, + "node_modules/@capgo/capacitor-social-login": { + "version": "8.3.36", + "resolved": "https://registry.npmjs.org/@capgo/capacitor-social-login/-/capacitor-social-login-8.3.36.tgz", + "integrity": "sha512-Y4HYjEJablzbHHwPBrbC2UvHVPsR0bAyCAqBzVBoUEOf0UFHAHyTP3gD9JUTKP/iERU8I+6IA2RWtLqDePCNuA==", + "license": "MPL-2.0", + "dependencies": { + "tslib": "^2.8.1" + }, + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", diff --git a/package.json b/package.json index b4f3dac..4109df8 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@capacitor/app": "^8.0.0", "@capacitor/core": "^8.3.4", "@capacitor/geolocation": "^8.2.0", + "@capgo/capacitor-social-login": "^8.3.36", "@quasar/extras": "^1.16.12", "@stomp/stompjs": "^7.3.0", "pinia": "^2.3.0", diff --git a/src/lib/googleAuth.ts b/src/lib/googleAuth.ts new file mode 100644 index 0000000..bfdb00c --- /dev/null +++ b/src/lib/googleAuth.ts @@ -0,0 +1,35 @@ +import { Capacitor } from '@capacitor/core' +import { SocialLogin } from '@capgo/capacitor-social-login' + +/** + * 네이티브(Capacitor) 구글 로그인. + * 웹뷰에서는 GIS(팝업/FedCM)가 동작하지 않으므로, 앱에서는 이 네이티브 흐름을 사용한다. + * 받은 ID 토큰은 웹 GIS 와 동일하게 백엔드 /api/auth/google 로 검증한다. + */ + +let initializedFor = '' + +/** 네이티브 플랫폼(iOS/Android) 여부 — 웹은 기존 GIS 사용. */ +export function isNativeGoogleAvailable(): boolean { + return Capacitor.isNativePlatform() +} + +/** + * 네이티브 구글 로그인 → ID 토큰 반환. + * @param webClientId 백엔드가 aud 검증에 쓰는 웹 클라이언트 ID (serverClientId) + */ +export async function signInWithGoogle(webClientId: string): Promise { + if (initializedFor !== webClientId) { + await SocialLogin.initialize({ google: { webClientId } }) + initializedFor = webClientId + } + const res = await SocialLogin.login({ + provider: 'google', + options: { scopes: ['email', 'profile'] }, + }) + const result = res.result as { idToken?: string | null } + if (!result?.idToken) { + throw new Error('구글 ID 토큰을 받지 못했습니다.') + } + return result.idToken +} diff --git a/src/pages/LoginPage.vue b/src/pages/LoginPage.vue index 208e976..8f4e6d4 100644 --- a/src/pages/LoginPage.vue +++ b/src/pages/LoginPage.vue @@ -12,8 +12,20 @@