[친구하자] Capacitor 앱에서 Kakao/Google 네이티브 로그인 구현 정리
in ProjectDiary
Capacitor로 빌드한 Android 앱에서 카카오/구글 네이티브 로그인을 구현한 방법에 대해 정리해보았습니다.
- Capacitor로 빌드한 React 앱에서 카카오와 구글 네이티브 로그인을 구현하는 방법을 정리해 보았다.
- 관련되서 정리되어있는게 없는것 같아서.. 내가 나중에 찾아볼 수 있게 일단 문서를 만들어보았다.
- 웹에서는 일반 OAuth 리다이렉트를 사용하지만, 모바일 앱에서는 네이티브 SDK를 직접 사용하는 방식으로 구현했다. (kakao, google)
- kakao developer에는 flutter문서에서 크로스 플랫폼에서는 커스텀 URL 스킴을 사용하라고 권장한다. 하지만 나는 플러그인을 사용하는 방식으로 구현해보았다.
네이티브 SDK 직접 사용 구헌 방식 (카카오, 구글)
네이티브 SDK 로그인 방식이란?
- 카카오/구글이 제공하는 Android/iOS 전용 SDK를 사용한 로그인 방식
- 앱 간 통신 방식을 사용한다.
- 즉, 기기에 설치된 카카오톡/구글 앱과 직접 통신하여 인증한다.
- WebView를 우회하여 브라우저 리다이렉트 없이 앱 레벨에서 토큰을 교환한다.
이 방식이 하이브리드 앱에서 가능한 이유
- ⭐️Capacitor의 플러그인 시스템⭐️이 핵심!

- WebView의 JavaScript 코드가 네이티브 코드를 호출할 수 있게 해줌
KakaoLoginPlugin.goLogin()을 통해 실제로 Android의 카카오 SDK 실행- 결과를 다시 JavaScript로 전달
*앱 구조 비교
// 안드로이드에서 실행 시
if (Capacitor.isNativePlatform()) {
// ✅ 네이티브 SDK 사용 (앱간 통신)
// 카카오톡 앱 → 내 앱 (빠르고 안정적)
const result = await KakaoLoginPlugin.goLogin();
}
// 웹 브라우저에서 실행 시
else {
// ✅ OAuth 리다이렉트 사용 (브라우저 기반)
// 브라우저 → 카카오 웹 → 콜백 URL
window.location.href = "https://kauth.kakao.com/oauth/...";
}
이렇게 하는 이유
- 네이티브 로그인의 장점:
- 사용자가 카카오톡이 설치되어 있으면 앱 전환만으로 즉시 로그인
- 브라우저 리다이렉트보다 UX가 훨씬 부드러움
- DeepLink, Custom URL Scheme 문제 없음
- 웹 로그인:
- 브라우저에서는 네이티브 SDK를 쓸 수 없으니 전통적인 OAuth 방식 사용
1. 카카오 네이티브 로그인 구현
1.1 플러그인 설치
pnpm add capacitor-kakao-login-plugin
npx cap sync
1.2 Android 설정
1.2.1 Kakao SDK 의존성 추가
android/app/build.gradle:
dependencies {
// ... 기존 의존성 ...
implementation "com.kakao.sdk:v2-common:2.20.1"
implementation "com.kakao.sdk:v2-auth:2.20.1"
}
android/build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
}
}
1.2.2 AndroidManifest.xml 설정
android/app/src/main/AndroidManifest.xml:
<application>
<!-- 카카오 SDK 메타데이터 -->
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="@string/kakao_app_key" />
<activity
android:name=".MainActivity"
android:exported="true">
<!-- 카카오 로그인 리다이렉트 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="kakaolink" android:scheme="@string/kakao_scheme" />
</intent-filter>
</activity>
<!-- 카카오 인증 코드 핸들러 -->
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="oauth" android:scheme="@string/kakao_scheme" />
</intent-filter>
</activity>
</application>
1.2.3 strings.xml 설정
android/app/src/main/res/values/strings.xml:
<resources>
<string name="kakao_app_key">YOUR_KAKAO_NATIVE_APP_KEY</string>
<string name="kakao_scheme">kakaoYOUR_KAKAO_NATIVE_APP_KEY</string>
</resources>
1.2.4 MainActivity.java 초기화
android/app/src/main/java/com/yourpackage/app/MainActivity.java:
import com.kakao.sdk.common.KakaoSdk;
public class MainActivity extends BridgeActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 카카오 SDK 초기화
KakaoSdk.init(this, getResources().getString(R.string.kakao_app_key));
}
}
1.3 iOS 설정
1.3.1 Info.plist 설정
ios/App/App/Info.plist:
<key>KAKAO_APP_KEY</key>
<string>YOUR_KAKAO_NATIVE_APP_KEY</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>kakaoYOUR_KAKAO_NATIVE_APP_KEY</string>
<string>com.yourapp.bundleid</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaoYOUR_KAKAO_NATIVE_APP_KEY</string>
<string>kakaokompassauth</string>
<string>storykompassauth</string>
<string>kakaolink</string>
<string>storylink</string>
<string>kakaotalk</string>
<string>kakaotalk-5.9.7</string>
<string>kakaostory-2.9.0</string>
</array>
1.3.2 AppDelegate.swift 초기화
ios/App/App/AppDelegate.swift:
import KakaoSDKAuth
import KakaoSDKCommon
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let key = Bundle.main.infoDictionary?["KAKAO_APP_KEY"] as? String
if let kakaoKey = key {
KakaoSDK.initSDK(appKey: kakaoKey)
}
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
if (AuthApi.isKakaoTalkLoginUrl(url)) {
return AuthController.handleOpenUrl(url: url)
}
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
1.4 프론트엔드 코드
client/lib/auth.ts:
import { KakaoLoginPlugin } from "capacitor-kakao-login-plugin";
export const startSocialLogin = async (
provider: OAuthProvider
): Promise<void> => {
const isMobile = Capacitor.isNativePlatform();
if (isMobile && provider === "kakao") {
try {
// 카카오 네이티브 로그인 실행
const kakaoResult = await KakaoLoginPlugin.goLogin();
// 카카오 액세스 토큰을 백엔드로 전달
const result = await processKakaoNativeLogin(kakaoResult.accessToken);
if (result) {
window.dispatchEvent(
new CustomEvent("oauth-login-success", {
detail: { userInfo: result.data.user_info },
})
);
}
} catch (error) {
window.dispatchEvent(
new CustomEvent("oauth-login-error", {
detail: { error: error.message },
})
);
}
} else {
// 웹: 일반 OAuth 리다이렉트
window.location.href = config.data.authorization_url;
}
};
// 백엔드로 카카오 토큰 전달
export const processKakaoNativeLogin = async (
kakaoAccessToken: string
): Promise<OAuthLoginResponse> => {
const response = await fetch(`${getApiUrl()}/v1/auth/oauth/kakao/native`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
kakao_access_token: kakaoAccessToken,
device_info: `${navigator.platform} - ${navigator.userAgent}`,
}),
credentials: "include",
});
return await response.json();
};
1.5 카카오 개발자 콘솔 설정
키 해시 등록 (Android)
- Android Studio Logcat에서 SHA-1, SHA-256 키 해시 확인
- 카카오 개발자 콘솔 → 내 애플리케이션 → 플랫폼 → Android → 키 해시 등록
리다이렉트 URI 설정
- Android:
kakao{NATIVE_APP_KEY}://oauth - iOS:
kakao{NATIVE_APP_KEY}://oauth
- Android:
2. 구글 네이티브 로그인 구현
2.1 플러그인 설치
pnpm add @codetrix-studio/capacitor-google-auth
npx cap sync
2.2 Google Console 설정
2.2.1 웹 클라이언트 ID 생성
- Google Console → API 및 서비스 → 사용자 인증 정보
- 사용자 인증 정보 만들기 → OAuth 2.0 클라이언트 ID
- 애플리케이션 유형: 웹 애플리케이션
- 생성된 클라이언트 ID를 복사
2.2.2 Android 클라이언트 ID 생성
- 사용자 인증 정보 만들기 → OAuth 2.0 클라이언트 ID
- 애플리케이션 유형: Android
- 패키지 이름:
com.yourapp.bundleid - SHA-1 인증서 지문 등록 (중요!)
SHA-1 지문 확인 방법:
# 디버그 키스토어
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
# 또는 MainActivity에서 로그로 확인
SHA-1 지문을 콜론 없이 등록
2.2.3 iOS 클라이언트 ID 생성 (선택)
- 사용자 인증 정보 만들기 → OAuth 2.0 클라이언트 ID
- 애플리케이션 유형: iOS
- 번들 ID:
com.yourapp.bundleid GoogleService.plist파일 다운로드
2.3 Android 설정
2.3.1 strings.xml 설정
android/app/src/main/res/values/strings.xml:
<resources>
<!-- 웹 클라이언트 ID (server_client_id) -->
<string name="server_client_id">YOUR_WEB_CLIENT_ID.apps.googleusercontent.com</string>
</resources>
참고: Android 클라이언트 ID는 코드에 넣을 필요 없습니다. 플러그인이 자동으로 사용합니다.
2.3.2 AndroidManifest.xml 권한 추가
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
2.3.3 capacitor.config.ts 설정
export default {
plugins: {
GoogleAuth: {
scopes: ["profile", "email"],
serverClientId: "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com",
forceCodeForRefreshToken: true,
},
},
};
2.4 iOS 설정
2.4.1 GoogleService.plist 추가
- Google Console에서 다운로드한
GoogleService.plist파일을 ios/App/App/폴더에 복사
2.4.2 Info.plist 설정
ios/App/App/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.yourapp.bundleid</string>
<!-- GoogleService.plist의 REVERSED_CLIENT_ID 값 -->
<string>YOUR_REVERSED_CLIENT_ID</string>
</array>
</dict>
</array>
REVERSED_CLIENT_ID는 GoogleService.plist 파일에서 확인할 수 있습니다.
2.5 프론트엔드 코드
client/lib/auth.ts:
import { GoogleAuth } from "@codetrix-studio/capacitor-google-auth";
export const startSocialLogin = async (
provider: OAuthProvider
): Promise<void> => {
const isMobile = Capacitor.isNativePlatform();
if (isMobile && provider === "google") {
try {
// 구글 플러그인 초기화 (scopes 포함)
await GoogleAuth.initialize({
scopes: ["profile", "email"],
});
// 구글 네이티브 로그인 실행
const googleResult = await GoogleAuth.signIn();
// 구글 ID 토큰을 백엔드로 전달
if (!googleResult.authentication?.idToken) {
throw new Error("구글 ID 토큰을 받지 못했습니다.");
}
const result = await processGoogleNativeLogin(
googleResult.authentication.idToken
);
if (result) {
window.dispatchEvent(
new CustomEvent("oauth-login-success", {
detail: { userInfo: result.data.user_info },
})
);
}
} catch (error) {
window.dispatchEvent(
new CustomEvent("oauth-login-error", {
detail: { error: error.message },
})
);
}
} else {
// 웹: 일반 OAuth 리다이렉트
window.location.href = config.data.authorization_url;
}
};
// 백엔드로 구글 ID 토큰 전달
export const processGoogleNativeLogin = async (
googleIdToken: string
): Promise<OAuthLoginResponse> => {
const response = await fetch(`${getApiUrl()}/v1/auth/oauth/google/native`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
google_id_token: googleIdToken,
device_info: `${navigator.platform} - ${navigator.userAgent}`,
}),
credentials: "include",
});
return await response.json();
};
2.6 웹 설정 (선택)
index.html:
<meta
name="google-signin-client_id"
content="YOUR_WEB_CLIENT_ID.apps.googleusercontent.com"
/>
3. 백엔드 API 엔드포인트
3.1 카카오 네이티브 로그인
POST /v1/auth/oauth/kakao/native
Content-Type: application/json
{
"kakao_access_token": "카카오_액세스_토큰",
"device_info": "플랫폼 정보"
}
3.2 구글 네이티브 로그인
POST /v1/auth/oauth/google/native
Content-Type: application/json
{
"google_id_token": "구글_ID_토큰",
"device_info": "플랫폼 정보"
}
4. 체크리스트
카카오 로그인
capacitor-kakao-login-plugin설치- Android: Kakao SDK 의존성 추가
- Android:
AndroidManifest.xml설정 - Android:
strings.xml에 앱 키 설정 - Android:
MainActivity.java에서 SDK 초기화 - iOS:
Info.plist설정 - iOS:
AppDelegate.swift에서 SDK 초기화 - 카카오 개발자 콘솔에 키 해시 등록
구글 로그인
@codetrix-studio/capacitor-google-auth설치- Google Console에 웹 클라이언트 ID 생성
- Google Console에 Android 클라이언트 ID 생성 (SHA-1 지문 등록)
- Google Console에 iOS 클라이언트 ID 생성 (선택)
- Android:
strings.xml에 웹 클라이언트 ID 설정 - Android:
capacitor.config.ts설정 - iOS:
GoogleService.plist추가 - iOS:
Info.plist에REVERSED_CLIENT_ID추가 - 웹:
index.html에 meta tag 추가