Facebook 로그인 설정
이 가이드에서는 Capgo 소셜 로그인으로 Facebook 로그인을 설정하는 방법을 알아봅니다. 다음이 필요합니다:
- Facebook 개발자 계정
- 앱의 패키지 이름/번들 ID
- 키 해시 생성을 위한 터미널에 대한 액세스(Android)
아직 Facebook 앱을 만들지 않았다면 다음 단계를 따르세요.
-
Facebook 앱 만들기
튜토리얼을 따라 앱 만들기
-
앱에 Facebook 로그인을 추가하세요.
Facebook 개발자 대시보드에서 앱에 Facebook 로그인 제품을 추가하세요.
-
앱을 대중에게 출시하기 전에 이 튜토리얼에 따라 게시하세요.
통합에 필요한 주요 정보를 찾을 수 있는 위치는 다음과 같습니다.
-
CLIENT_TOKEN:
-
APP_ID:
-
APP_NAME:
Android 설정
Section titled “Android 설정”-
AndroidManifest.xml에 인터넷 권한을 추가하세요.다음 줄이 있는지 확인하세요.
<uses-permission android:name="android.permission.INTERNET"/> -
Android 키 해시를 생성하세요.
이는 Facebook에 필요한 중요한 보안 단계입니다. 터미널을 열고 다음을 실행하세요.
Terminal window keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 -A비밀번호를 묻는 메시지가 나타나면 다음을 사용하세요:
android:::참고 릴리스 빌드의 경우 릴리스 키 저장소를 사용해야 합니다.
Terminal window keytool -exportcert -alias your-key-name -keystore your-keystore-path | openssl sha1 -binary | openssl base64 -A:::
-
Facebook 앱에 키 해시를 추가하세요.
- Facebook 개발자의 앱 대시보드로 이동합니다.
- 설정 > 기본으로 이동합니다.
- “Android” 섹션까지 아래로 스크롤합니다.
- Android이 아직 추가되지 않은 경우 “플랫폼 추가”를 클릭하고 세부 정보를 입력하세요.
- 생성한 키 해시를 추가하세요.
- 프로덕션의 경우 디버그 및 릴리스 키 해시를 모두 추가합니다.
-
다음을 포함하도록
AndroidManifest.xml을 업데이트하세요.<application>...<activity android:name="com.facebook.FacebookActivity"android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"android:label="@string/app_name" /><activityandroid:name="com.facebook.CustomTabActivity"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:scheme="FB[APP_ID]" /></intent-filter></activity></application>:::주의
android:scheme속성에서[APP_ID]을 실제 Facebook 앱 ID로 바꿔야 합니다. :::
iOS 설정
Section titled “iOS 설정”-
Facebook 개발자 콘솔에 iOS 플랫폼을 추가합니다.
- Facebook 개발자의 앱 대시보드로 이동합니다.
- 설정 > 기본으로 이동합니다.
- 페이지 맨 아래까지 스크롤한 후 ‘플랫폼 추가’를 클릭하세요.
- iOS을 선택하고 필수 세부정보를 입력하세요.
-
Xcode 프로젝트를 열고 Info.plist로 이동합니다.
-
Info.plist에 다음 항목을 추가합니다.
<key>FacebookAppID</key><string>[APP-ID]</string><key>FacebookClientToken</key><string>[CLIENT-TOKEN]</string><key>FacebookDisplayName</key><string>[APP-NAME]</string><key>LSApplicationQueriesSchemes</key><array><string>fbapi</string><string>fb-messenger-share-api</string></array><key>CFBundleURLTypes</key><array><dict><key>CFBundleURLSchemes</key><array><string>fb[APP-ID]</string></array></dict></array>:::주의 다음 값을 바꿉니다.
[APP-ID](Facebook 앱 ID 포함)- 클라이언트 토큰으로
[CLIENT-TOKEN] [APP-NAME]를 앱 이름으로 포함 :::
-
AppDelegate.swift수정import FBSDKCoreKit@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// Override point for customization after application launch.// Initialize Facebook SDKFBSDKCoreKit.ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)return true}func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {// Called when the app was launched with a url. Feel free to add additional processing here,// but if you want the App API to support tracking app url opens, make sure to keep this callif (FBSDKCoreKit.ApplicationDelegate.shared.application(app,open: url,sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,annotation: options[UIApplication.OpenURLOptionsKey.annotation])) {return true;} else {return ApplicationDelegateProxy.shared.application(app, open: url, options: options)}}}
앱에서 Facebook 로그인 사용:::caution
Section titled “앱에서 Facebook 로그인 사용:::caution”시작하기 전에: 새로운 Facebook SDK을 사용하면 받는 토큰 유형은 코드 구성이 아니라 전적으로 사용자의 앱 추적 선택에 따라 달라집니다. 모든 사용자에 대해 인증이 작동하도록 항상 백엔드에 액세스 토큰과 JWT 토큰 처리를 모두 구현하십시오. :::
-
앱에서 Facebook 로그인을 초기화합니다.
import { SocialLogin } from '@capgo/capacitor-social-login';// Initialize during app startupawait SocialLogin.initialize({facebook: {appId: 'APP_ID',clientToken: 'CLIENT_TOKEN',}}) -
로그인 기능 구현
async function loginWithFacebook() {try {const result = await SocialLogin.login({provider: 'facebook',options: {permissions: ['email', 'public_profile'],limitedLogin: false // See Limited Login section below for important details}});console.log('Facebook login result:', result);// Handle successful login} catch (error) {console.error('Facebook login error:', error);// Handle error}}:::참고 제한된 로그인(iOS 전용): Facebook의 제한된 로그인 기능을 사용하려면
limitedLogin을 true로 설정하세요. 이는 로그인 시 공유되는 데이터를 제한하여 강화된 개인정보 보호를 제공하는 iOS 전용 기능입니다.중요 제한 사항:
- iOS만: 제한된 로그인은 iOS 장치에만 영향을 미치고 Android에는 영향을 미치지 않습니다.
- ATT 재정의:
limitedLogin: false을 설정하더라도 사용자가 앱 추적 투명성(ATT) 권한을 부여하지 않은 경우 Facebook은 자동으로true로 강제 설정합니다. - 항상 두 가지 사례 모두 처리: 앱은 항상 제한된 로그인 시나리오와 전체 로그인 시나리오를 모두 처리할 준비가 되어 있어야 합니다.
ATT 상태 확인 중:
// Check if user has granted tracking permissionconst trackingStatus = await SocialLogin.providerSpecificCall({call: 'facebook#requestTracking',options: {}});console.log('Tracking status:', trackingStatus.status); // 'authorized', 'denied', 'notDetermined', or 'restricted'access_token이 선호되는 경우 권장되는 구현:
async function loginWithFacebook() {try {// Check ATT status firstconst trackingStatus = await SocialLogin.providerSpecificCall({call: 'facebook#requestTracking',options: {}});const result = await SocialLogin.login({provider: 'facebook',options: {permissions: ['email', 'public_profile'],limitedLogin: trackingStatus.status === 'denied' // Auto-adjust based on ATT}});// Handle different response types based on limited loginif (result.result.accessToken) {// Your app logic should work with both limited and full loginconsole.log('Login successful:', result);}} catch (error) {console.error('Facebook login error:', error);}}제한된 로그인에서는 어떤 일이 발생합니까?
- 데이터 액세스 감소: 일부 사용자 데이터를 사용하지 못할 수 있습니다.
- 다른 토큰 유형: 액세스 토큰은 다른 기능을 가질 수 있습니다.
- 개인 정보 보호 규정 준수: iOS 개인 정보 보호 요구 사항을 준수하는 데 도움이 됩니다.
중요: 항상 제한된 로그인 시나리오와 전체 로그인 시나리오를 모두 사용하여 앱을 테스트하여 두 경우 모두에서 앱이 올바르게 작동하는지 확인하세요. 제한된 로그인에 대한 자세한 내용은 여기에서 확인할 수 있습니다. :::
-
사용자 프로필 데이터 가져오기
로그인에 성공하면 추가 프로필 정보를 검색할 수 있습니다.
async function getFacebookProfile() {try {const profileResponse = await SocialLogin.providerSpecificCall({call: 'facebook#getProfile',options: {fields: ['id', 'name', 'email', 'first_name', 'last_name', 'picture']}});console.log('Facebook profile:', profileResponse.profile);return profileResponse.profile;} catch (error) {console.error('Failed to get Facebook profile:', error);return null;}}// Example usage after loginasync function loginAndGetProfile() {const loginResult = await loginWithFacebook();if (loginResult) {const profile = await getFacebookProfile();if (profile) {console.log('User ID:', profile.id);console.log('Name:', profile.name);console.log('Email:', profile.email);console.log('Profile Picture:', profile.picture?.data?.url);}}}:::팁 사용 가능한 프로필 필드: Facebook의 그래프 API에서 사용 가능한 모든 필드를 요청할 수 있습니다. 일반적인 필드에는
id,name,email,first_name,last_name,picture,birthday,gender,location,hometown. 일부 필드에는 추가 권한이 필요할 수 있습니다. ::::::경고 토큰 유형 제한:
getProfile호출은 액세스 토큰(추적이 허용되는 표준 로그인)이 있는 경우에만 작동합니다. 사용자가 추적을 거부했거나 제한된 로그인(JWT 토큰만 해당)을 사용하는 경우 이 호출은 실패합니다. 이 경우 초기 로그인 응답에 제공된 프로필 데이터를 사용하세요. :::
⚠️ 중요: 백엔드 토큰 처리
Section titled “⚠️ 중요: 백엔드 토큰 처리”iOS 사용자는 앱 추적 투명성 선택에 따라 액세스 토큰 또는 JWT 토큰을 받을 수 있고 Android 사용자는 항상 액세스 토큰을 받기 때문에 백엔드는 두 가지 다른 토큰 유형을 처리해야 합니다.
플랫폼별 토큰 유형
Section titled “플랫폼별 토큰 유형”| 플랫폼 | Limited로그인 설정 | 사용자 ATT 선택 | 결과 토큰 유형 |
|---|---|---|---|
| iOS | true | 모두 | JWT 토큰 |
| iOS | false | 추적 허용 | 액세스 토큰 |
| iOS | false | 추적 거부 | JWT 토큰(자동 재정의) |
| Android | 모두 | 해당 없음 | 액세스 토큰(항상) |
백엔드 구현
Section titled “백엔드 구현”-
토큰 유형을 감지하고 이에 따라 처리
async function loginWithFacebook() {try {const loginResult = await SocialLogin.login({provider: 'facebook',options: {permissions: ['email', 'public_profile'],limitedLogin: false // iOS: depends on ATT, Android: ignored}});if (loginResult.accessToken) {// Access token (Android always, iOS when tracking allowed)return handleAccessToken(loginResult.accessToken.token);} else if (loginResult.idToken) {// JWT token (iOS only when tracking denied or limitedLogin: true)return handleJWTToken(loginResult.idToken);}} catch (error) {console.error('Facebook login error:', error);}} -
Firebase 통합 예
import { OAuthProvider, FacebookAuthProvider, signInWithCredential } from 'firebase/auth';async function handleAccessToken(accessToken: string, nonce: string) {// For access tokens, use OAuthProvider (new method)const fbOAuth = new OAuthProvider("facebook.com");const credential = fbOAuth.credential({idToken: accessToken,rawNonce: nonce});try {const userResponse = await signInWithCredential(auth, credential);return userResponse;} catch (error) {console.error('Firebase OAuth error:', error);return false;}}async function handleJWTToken(jwtToken: string) {// For JWT tokens, send to your backend for validationtry {const response = await fetch('/api/auth/facebook-jwt', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({ jwtToken })});const result = await response.json();return result;} catch (error) {console.error('JWT validation error:', error);return false;}} -
백엔드 JWT 검증
// Backend: Validate JWT token from Facebookimport jwt from 'jsonwebtoken';import { Request, Response } from 'express';app.post('/api/auth/facebook-jwt', async (req: Request, res: Response) => {const { jwtToken } = req.body;try {// Verify JWT token with Facebook's public key// See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claimsconst decoded = jwt.verify(jwtToken, getFacebookPublicKey(), {algorithms: ['RS256'],audience: process.env.FACEBOOK_APP_ID,issuer: 'https://www.facebook.com' // From: https://www.facebook.com/.well-known/openid-configuration/?_rdr});// Extract user info from JWTconst userInfo = {id: decoded.sub,email: decoded.email,name: decoded.name,isJWTAuth: true};// Create your app's session/tokenconst sessionToken = createUserSession(userInfo);res.json({success: true,token: sessionToken,user: userInfo});} catch (error) {console.error('JWT validation failed:', error);res.status(401).json({ success: false, error: 'Invalid token' });}}); -
일반 백엔드 토큰 핸들러
// Handle both token types in your backendasync function authenticateFacebookUser(tokenData: any) {if (tokenData.accessToken) {// Handle access token - validate with Facebook Graph APIconst response = await fetch(`https://graph.facebook.com/me?access_token=${tokenData.accessToken}&fields=id,name,email`);const userInfo = await response.json();return {user: userInfo,tokenType: 'access_token',expiresIn: tokenData.expiresIn || 3600};} else if (tokenData.jwtToken) {// Handle JWT token - decode and validate// See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claimsconst decoded = jwt.verify(tokenData.jwtToken, getFacebookPublicKey());return {user: {id: decoded.sub,name: decoded.name,email: decoded.email},tokenType: 'jwt',expiresIn: decoded.exp - Math.floor(Date.now() / 1000)};} else {throw new Error('No valid token provided');}}
주요 고려사항
Section titled “주요 고려사항”액세스 토큰(표준 로그인):
- ✅ Android: 항상 사용 가능(iOS 전용 제한 사항은 적용되지 않음)
- ✅ iOS: 사용자가 명시적으로 앱 추적을 허용한 경우에만
- ✅ Facebook 그래프 API에 액세스하는 데 사용할 수 있습니다.
- ✅ 만료 시간 연장
- ✅ 더 많은 사용자 데이터 사용 가능
- ❌ 사용자가 점점 추적을 거부함에 따라 iOS에서는 덜 일반적이 됨
JWT 토큰(iOS-전용 개인 정보 보호 모드):
- ❌ Android: 발생하지 않음(지원되지 않음)
- ✅ iOS: 추적이 거부되거나
limitedLogin: true하는 경우 - ✅ iOS 사용자 개인 정보 보호 기본 설정을 존중합니다.
- ❌ 기본 사용자 정보만 포함되어 있습니다.
- ❌ 만료 시간 단축
- ❌ Facebook 그래프 API에 액세스할 수 없습니다.
- ⚠️ 이제 iOS 사용자를 위한 가장 일반적인 시나리오
플랫폼별 동작:
- iOS 앱: 액세스 토큰과 JWT 토큰을 모두 처리해야 합니다.
- Android 앱: 액세스 토큰만 처리하면 됩니다.
- 교차 플랫폼 앱: 두 가지 토큰 처리 방법을 모두 구현해야 합니다.
보안 컨텍스트 요구 사항(웹/Capacitor)
Section titled “보안 컨텍스트 요구 사항(웹/Capacitor)”암호화폐 API 제한 사항
Section titled “암호화폐 API 제한 사항”업데이트된 Facebook 로그인 흐름에는 nonce 생성을 위한 Web Crypto API가 필요하며 이는 보안 컨텍스트에서만 사용할 수 있습니다.
// This requires secure context (HTTPS or localhost)async function sha256(message: string) { const msgBuffer = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); // ❌ Fails in insecure context // ...}개발 환경 문제
Section titled “개발 환경 문제”일반적인 문제: HTTP URL이 포함된 ionic Serve로 인해 Facebook 인증이 중단됩니다.
| 환경 | 암호화폐 API 사용 가능 | Facebook 로그인 작동 |
|---|---|---|
http://localhost:3000 | ✅ 예 | ✅ 예 |
http://127.0.0.1:3000 | ✅ 예 | ✅ 예 |
http://192.168.1.100:3000 | ❌ 아니요 | ❌ 아니요 |
https://any-domain.com | ✅ 예 | ✅ 예 |
Capacitor 개발을 위한 솔루션
Section titled “Capacitor 개발을 위한 솔루션”-
웹 테스트에 localhost 사용
Terminal window # Instead of ionic serve --host=0.0.0.0ionic serve --host=localhost -
Ionic에서 HTTPS 활성화
Terminal window ionic serve --ssl -
실제 기기에서 테스트
Terminal window # Capacitor apps run in secure context on devicesionic cap run iosionic cap run android -
개발을 위한 대체 nonce 생성
async function generateNonce() {if (typeof crypto !== 'undefined' && crypto.subtle) {// Secure context - use crypto.subtlereturn await sha256(Math.random().toString(36).substring(2, 10));} else {// Fallback for development (not secure for production)console.warn('Using fallback nonce - not secure for production');return btoa(Math.random().toString(36).substring(2, 10));}}
Firebase 통합 참고 사항
Section titled “Firebase 통합 참고 사항”최근 Firebase 문서에는 로그인 설정에 관계없이 Facebook 인증을 위한 nonce가 있는 JWT 토큰이 필요합니다. 이 접근 방식은 limitedLogin: true 및 limitedLogin: false 모두에서 작동합니다.
// Both modes can return JWT tokens depending on user choice const loginResult = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false, // true = always JWT, false = depends on user tracking choice nonce: nonce } });개발 제한 사항: 네트워크 IP(로컬 호스트 아님)에서 ionic Serve를 사용하는 경우 암호화 API 제한으로 인해 Facebook 로그인이 실패합니다. 웹 테스트에는 localhost 또는 HTTPS를 사용하십시오.
일반적인 문제 및 해결 방법
Section titled “일반적인 문제 및 해결 방법”-
Android의 키 해시 오류
- Facebook 대시보드에 올바른 키 해시를 추가했는지 다시 확인하세요.
- 릴리스 빌드의 경우 디버그 및 릴리스 키 해시를 모두 추가했는지 확인하세요.
- 해시를 생성할 때 올바른 키 저장소를 사용하고 있는지 확인하세요.
-
Facebook 로그인 버튼이 나타나지 않습니다
- 모든 매니페스트 항목이 올바른지 확인하세요.
- Facebook 앱 ID와 클라이언트 토큰이 올바른지 확인하세요.
- SDK을 올바르게 초기화했는지 확인하세요.
-
일반적인 iOS 문제
- 모든 Info.plist 항목이 올바른지 확인하세요.
- URL 구성표가 올바르게 구성되었는지 확인
- 번들 ID가 Facebook 대시보드에 등록된 ID와 일치하는지 확인하세요.
-
테스트하기 전에 Facebook 개발자 콘솔에서 테스트 사용자를 추가하세요
- 역할 > 테스트 사용자로 이동합니다.
- 테스트 사용자 생성
- 테스트에 이 자격 증명을 사용하십시오.
-
디버그 및 릴리스 빌드 모두 테스트
- 디버그 키 해시를 사용한 디버그 빌드
- 릴리스 키 해시를 사용한 릴리스 빌드
- 에뮬레이터와 실제 장치 모두에서 테스트다음을 포함하여 전체 로그인 흐름을 테스트하는 것을 잊지 마세요.
- 로그인 성공
- 로그인 취소
- 오류 처리
- 로그아웃 기능