콘텐츠로 건너뛰기

Facebook 로그인 설정

이 가이드에서는 Capgo 소셜 로그인으로 Facebook 로그인을 설정하는 방법을 알아봅니다. 다음이 필요합니다:

  • Facebook 개발자 계정
  • 앱의 패키지 이름/번들 ID
  • 키 해시 생성을 위한 터미널에 대한 액세스(Android)

아직 Facebook 앱을 만들지 않았다면 다음 단계를 따르세요.

  1. Facebook 앱 만들기

    튜토리얼을 따라 앱 만들기

  2. 앱에 Facebook 로그인을 추가하세요.

    Facebook 개발자 대시보드에서 앱에 Facebook 로그인 제품을 추가하세요.

  3. 앱을 대중에게 출시하기 전에 이 튜토리얼에 따라 게시하세요.

통합에 필요한 주요 정보를 찾을 수 있는 위치는 다음과 같습니다.

  1. CLIENT_TOKEN:

    Facebook 클라이언트 토큰을 찾을 수 있는 위치를 보여주는 개발자 대시보드
  2. APP_ID:

    Facebook 앱 ID를 찾을 수 있는 위치를 보여주는 개발자 대시보드
  3. APP_NAME:

    Facebook 앱 이름을 찾을 수 있는 위치를 보여주는 개발자 대시보드
  1. AndroidManifest.xml에 인터넷 권한을 추가하세요.

    다음 줄이 있는지 확인하세요.

    <uses-permission android:name="android.permission.INTERNET"/>
  2. 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

    :::

  3. Facebook 앱에 키 해시를 추가하세요.

    1. Facebook 개발자의 앱 대시보드로 이동합니다.
    2. 설정 > 기본으로 이동합니다.
    3. “Android” 섹션까지 아래로 스크롤합니다.
    4. Android이 아직 추가되지 않은 경우 “플랫폼 추가”를 클릭하고 세부 정보를 입력하세요.
    5. 생성한 키 해시를 추가하세요.
    6. 프로덕션의 경우 디버그 및 릴리스 키 해시를 모두 추가합니다.
  4. 다음을 포함하도록 AndroidManifest.xml을 업데이트하세요.

    <application>
    ...
    <activity android:name="com.facebook.FacebookActivity"
    android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
    android:label="@string/app_name" />
    <activity
    android: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로 바꿔야 합니다. :::

  1. Facebook 개발자 콘솔에 iOS 플랫폼을 추가합니다.

    1. Facebook 개발자의 앱 대시보드로 이동합니다.
    2. 설정 > 기본으로 이동합니다.
    3. 페이지 맨 아래까지 스크롤한 후 ‘플랫폼 추가’를 클릭하세요.
    4. iOS을 선택하고 필수 세부정보를 입력하세요.
  2. Xcode 프로젝트를 열고 Info.plist로 이동합니다.

  3. 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]를 앱 이름으로 포함 :::
  4. AppDelegate.swift 수정

    import FBSDKCoreKit
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    // Initialize Facebook SDK
    FBSDKCoreKit.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 call
    if (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 토큰 처리를 모두 구현하십시오. :::

  1. 앱에서 Facebook 로그인을 초기화합니다.

    import { SocialLogin } from '@capgo/capacitor-social-login';
    // Initialize during app startup
    await SocialLogin.initialize({
    facebook: {
    appId: 'APP_ID',
    clientToken: 'CLIENT_TOKEN',
    }
    })
  2. 로그인 기능 구현

    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 permission
    const 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 first
    const 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 login
    if (result.result.accessToken) {
    // Your app logic should work with both limited and full login
    console.log('Login successful:', result);
    }
    } catch (error) {
    console.error('Facebook login error:', error);
    }
    }

    제한된 로그인에서는 어떤 일이 발생합니까?

    • 데이터 액세스 감소: 일부 사용자 데이터를 사용하지 못할 수 있습니다.
    • 다른 토큰 유형: 액세스 토큰은 다른 기능을 가질 수 있습니다.
    • 개인 정보 보호 규정 준수: iOS 개인 정보 보호 요구 사항을 준수하는 데 도움이 됩니다.

    중요: 항상 제한된 로그인 시나리오와 전체 로그인 시나리오를 모두 사용하여 앱을 테스트하여 두 경우 모두에서 앱이 올바르게 작동하는지 확인하세요. 제한된 로그인에 대한 자세한 내용은 여기에서 확인할 수 있습니다. :::

  3. 사용자 프로필 데이터 가져오기

    로그인에 성공하면 추가 프로필 정보를 검색할 수 있습니다.

    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 login
    async 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 토큰만 해당)을 사용하는 경우 이 호출은 실패합니다. 이 경우 초기 로그인 응답에 제공된 프로필 데이터를 사용하세요. :::

iOS 사용자는 앱 추적 투명성 선택에 따라 액세스 토큰 또는 JWT 토큰을 받을 수 있고 Android 사용자는 항상 액세스 토큰을 받기 때문에 백엔드는 두 가지 다른 토큰 유형을 처리해야 합니다.

플랫폼Limited로그인 설정사용자 ATT 선택결과 토큰 유형
iOStrue모두JWT 토큰
iOSfalse추적 허용액세스 토큰
iOSfalse추적 거부JWT 토큰(자동 재정의)
Android모두해당 없음액세스 토큰(항상)
  1. 토큰 유형을 감지하고 이에 따라 처리

    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);
    }
    }
  2. 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 validation
    try {
    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;
    }
    }
  3. 백엔드 JWT 검증

    // Backend: Validate JWT token from Facebook
    import 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-claims
    const 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 JWT
    const userInfo = {
    id: decoded.sub,
    email: decoded.email,
    name: decoded.name,
    isJWTAuth: true
    };
    // Create your app's session/token
    const 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' });
    }
    });
  4. 일반 백엔드 토큰 핸들러

    // Handle both token types in your backend
    async function authenticateFacebookUser(tokenData: any) {
    if (tokenData.accessToken) {
    // Handle access token - validate with Facebook Graph API
    const 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-claims
    const 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');
    }
    }

액세스 토큰(표준 로그인):

  • Android: 항상 사용 가능(iOS 전용 제한 사항은 적용되지 않음)
  • iOS: 사용자가 명시적으로 앱 추적을 허용한 경우에만
  • ✅ Facebook 그래프 API에 액세스하는 데 사용할 수 있습니다.
  • ✅ 만료 시간 연장
  • ✅ 더 많은 사용자 데이터 사용 가능
  • 사용자가 점점 추적을 거부함에 따라 iOS에서는 덜 일반적이 됨

JWT 토큰(iOS-전용 개인 정보 보호 모드):

  • Android: 발생하지 않음(지원되지 않음)
  • iOS: 추적이 거부되거나 limitedLogin: true하는 경우
  • ✅ iOS 사용자 개인 정보 보호 기본 설정을 존중합니다.
  • ❌ 기본 사용자 정보만 포함되어 있습니다.
  • ❌ 만료 시간 단축
  • ❌ Facebook 그래프 API에 액세스할 수 없습니다.
  • ⚠️ 이제 iOS 사용자를 위한 가장 일반적인 시나리오

플랫폼별 동작:

  • iOS 앱: 액세스 토큰과 JWT 토큰을 모두 처리해야 합니다.
  • Android 앱: 액세스 토큰만 처리하면 됩니다.
  • 교차 플랫폼 앱: 두 가지 토큰 처리 방법을 모두 구현해야 합니다.

보안 컨텍스트 요구 사항(웹/Capacitor)

Section titled “보안 컨텍스트 요구 사항(웹/Capacitor)”

업데이트된 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
// ...
}

일반적인 문제: 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✅ 예✅ 예
  1. 웹 테스트에 localhost 사용

    Terminal window
    # Instead of ionic serve --host=0.0.0.0
    ionic serve --host=localhost
  2. Ionic에서 HTTPS 활성화

    Terminal window
    ionic serve --ssl
  3. 실제 기기에서 테스트

    Terminal window
    # Capacitor apps run in secure context on devices
    ionic cap run ios
    ionic cap run android
  4. 개발을 위한 대체 nonce 생성

    async function generateNonce() {
    if (typeof crypto !== 'undefined' && crypto.subtle) {
    // Secure context - use crypto.subtle
    return 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 문서에는 로그인 설정에 관계없이 Facebook 인증을 위한 nonce가 있는 JWT 토큰이 필요합니다. 이 접근 방식은 limitedLogin: truelimitedLogin: 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를 사용하십시오.

  1. Android의 키 해시 오류

    • Facebook 대시보드에 올바른 키 해시를 추가했는지 다시 확인하세요.
    • 릴리스 빌드의 경우 디버그 및 릴리스 키 해시를 모두 추가했는지 확인하세요.
    • 해시를 생성할 때 올바른 키 저장소를 사용하고 있는지 확인하세요.
  2. Facebook 로그인 버튼이 나타나지 않습니다

    • 모든 매니페스트 항목이 올바른지 확인하세요.
    • Facebook 앱 ID와 클라이언트 토큰이 올바른지 확인하세요.
    • SDK을 올바르게 초기화했는지 확인하세요.
  3. 일반적인 iOS 문제

    • 모든 Info.plist 항목이 올바른지 확인하세요.
    • URL 구성표가 올바르게 구성되었는지 확인
    • 번들 ID가 Facebook 대시보드에 등록된 ID와 일치하는지 확인하세요.
  1. 테스트하기 전에 Facebook 개발자 콘솔에서 테스트 사용자를 추가하세요

    • 역할 > 테스트 사용자로 이동합니다.
    • 테스트 사용자 생성
    • 테스트에 이 자격 증명을 사용하십시오.
  2. 디버그 및 릴리스 빌드 모두 테스트

    • 디버그 키 해시를 사용한 디버그 빌드
    • 릴리스 키 해시를 사용한 릴리스 빌드
    • 에뮬레이터와 실제 장치 모두에서 테스트다음을 포함하여 전체 로그인 흐름을 테스트하는 것을 잊지 마세요.
  • 로그인 성공
  • 로그인 취소
  • 오류 처리
  • 로그아웃 기능