기록의 습관화
article thumbnail

전에 RN을 이용해서 프로젝트를 진행해 본 경험이 있는데

너무나도 많은 오류를 봐서 손 놓고 있었는데 요번 프로젝트에서도

webView와 firebase OAuth를 이용할 일이 생겨서 다시 손을 잡게 되었습니다...

 

이번 포스트에서는 firebase + expo auth를 이용해서 소셜 로그인을 구현하는 방법을 다뤄보려고 합니다.

좀 더 프로젝트 setting을 편하게 가져가보려다가 역시나 많은 오류를 만났기에 😂

그럼 같이 차근차근 해나 가볼까요?

 

환경은

expo : ~48.0.15

react-native : 0.71.1

react : 18.2.0

입니다.

 

 

요번에 expo sdk48에서 새로운 기능으로

expo-router가 새로 나와 프로젝트에 적용해 본 버전입니다.

 

기본적인 expo 설치의 경우 아래의 공식 문서를 참고하시면 됩니다.

https://docs.expo.dev/get-started/create-a-project/

 

Create a project

Learn how to create a new Expo project and run it on your device.

docs.expo.dev

https://blog.expo.dev/expo-sdk-48-ccb8302e231

 

Expo SDK 48

Today we’re announcing the release of Expo SDK 48. SDK 48 includes React Native 0.71.3. Thank you to everyone who helped with beta testing.

blog.expo.dev


1. firebase 설치

이 또한 공식문서에 잘 나와있습니다.

특별한 사항으로는 중간에 metro.config.js를 설정하는 부분이 있는데

이게 왜 필요하냐면

 

firebase의 경우 native 모듈의 기능을 사용해야 하는 부분이 많은데

이 모듈들은 Expo의 기본 세팅만으로는 완전하게 동작하지 않습니다.

그렇기에 다음과 같은 설정을 통해서 native 모듈의 기능을 사용하게 해 주는 거죠

 

const { getDefaultConfig } = require('@expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

module.exports = {
  resolver: {
    ...defaultConfig.resolver,
    sourceExts: [...defaultConfig.resolver.sourceExts, 'cjs'],
  },
  transformer: {
    ...defaultConfig.transformer,
    babelTransformerPath: require.resolve('expo-module-scripts/babel-transformer'),
  },
};
  • sourceExts : CommonJS 모듈을 사용할 수 있도록 해줌
  • babelTransformerPath : Metro 번들러에게 Expo가 제공하는 Babel Transformer를 사용하도록 해줌

 

그렇다면 Metro 번들러가 뭘까요?
FaceBook에서 제공한 JS 번들러로 RN을 위한 모듈 번들링 및 변환을 처리해 줍니다.
번들러는 모든 JS 파일과 의존성을 하나의 번들로 결합해 주는 거죠.
Metro 번들러가 제공하는 기능으로는
1. 빠른 변환 : 캐싱을 지원하여 빠른 코드 변환
2. hot-reload : 저희가 저장을 하면 변경사항만 반영되도록
3. Asset 처리 : 이미지, 폰트 정적 리소스 처리 및 모듈로의 변환
4. 소스 맵 생성 : 디버깅에 도움이 되는 소스 맵을 생성 하여 원본 코드와 변환 코드 사이의 매핑 제공

위와 같은 역할을 하는 게 Metro 번들러입니다.


2. 구글 로그인 연동

구글 로그인의 경우 expo에서 expo-auth-session을 지원합니다.

 

https://docs.expo.dev/versions/latest/sdk/auth-session/

 

AuthSession

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

 

필요한 clientId의 경우 구글 cloud에서 추가가 가능하며

다음과 같은 과정을 통해 확인하실 수 있습니다.

1. Google Cloud 접속 

https://console.cloud.google.com/apis/credentials/oauthclient

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

2. 프로젝트가 없다면 프로젝트 생성

3. 사용자 인증 정보

4. 클라이언트 ID 정보 복사

5. 승인된 자바스크립트 원본에 expo 추가

6. 승인된 리디렉션 URI 추가

그리고 다음과 같이 코드를 사용해 주면 됩니다.

 

간단하게 코드를 설명하면 

1. 지정된 googleClient를 기반으로 웹뷰 로그인을 요청하고

2. 로그인이 성공한다면 로그인 정보를 가지고 firebase에 로그인 정보를 전송

하는 로직입니다. 

 

더보기
import * as WebBrowser from 'expo-web-browser';
import * as Google from 'expo-auth-session/providers/google';

import {
  getAuth,
  GoogleAuthProvider,
  signInWithCredential,
  onAuthStateChanged,
} from 'firebase/auth';

WebBrowser.maybeCompleteAuthSession();

import { useEffect } from 'react';

const useGetGoogleAuth = () => {
  const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
    clientId: process.env.GOOGLE_CLIENT_ID,
  });
  const auth = getAuth();

  useEffect(() => {
    if (response?.type === 'success') {
      const { id_token } = response.params;
      const credential = GoogleAuthProvider.credential(id_token);
      signInWithCredential(auth, credential);
    }
  }, [response]);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, async (user) => {
      if (user) {
        const { uid, email, displayName, refreshToken } = user;
        console.log('uid :', uid);
        console.log('email :', email);
        console.log('displayName :', displayName);
        console.log('refreshToken :', refreshToken);
      }
    });
    return () => {
      unsubscribe();
    };
  }, [auth]);

  return { request, response, promptAsync };
};

export default useGetGoogleAuth;

 

 

이렇게 하면 구글 로그인이 정상적으로 동작하는 걸 확인할 수 있습니다. 😃


3. 애플 로그인

요번에 좀 난관을 많이 겪은 부분입니다. ㅠㅠ

애플 로그인의 경우 expo 환경에서 지원을 해줍니다. 이전에는 rn의 기본을 사용해서 사용했는데

확실히 편하긴 하더라고요

 

주의점은 ios의 경우 개발자 계정이 필요합니다. 

1년에 13만 원 정도의 값을 지불하고 앱을 올릴 수 있는 혜택?을 주는데

없으시다면 등록을 하셔야 앱을 올릴 수 있습니다.

 

그다음 과정으로 앱 정보를 등록해 주고 Credentials를 설정해야 하는데

이는 다른 링크를 참고하였습니다.

과정이 조금 복잡하니 순서대로 잘 따라 하시면 됩니다.

https://imweb.me/faq?mode=view&category=29&category2=47&idx=71719 

 

애플 로그인 설정하기

참고: 같은 이름(닉네임)으로 중복 가입 방지 옵션을 해제해 주세요. 소셜 로그인 가입자는 대부분 가입된 플랫폼의 이름(닉네임)을 그대로 사용하는 경향이 있으며, 소셜 로그인 플랫

imweb.me

대기업의 횡포

 

다음으로는 expo에서 이를 사용해 줘야겠죠

 

https://docs.expo.dev/versions/latest/sdk/apple-authentication/

 

AppleAuthentication

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

 

1. 라이브러리 설치

npx expo install expo-apple-authentication

2. 공식 문서 내용대로 Apple 로그인 버튼 추가

 

3. 코드 추가

아까 구글 로그인과 로직은 동일합니다.

더보기
import * as AppleAuthentication from 'expo-apple-authentication';
import {
  getAuth,
  signInWithCredential,
  OAuthProvider,
  onAuthStateChanged,
  OAuthCredential,
} from 'firebase/auth';
import { useEffect } from 'react';

const useGetAppleAuth = () => {
  const auth = getAuth();

  const signInWithApple = async () => {
    try {
      const result = await AppleAuthentication.signInAsync({
        requestedScopes: [
          AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
          AppleAuthentication.AppleAuthenticationScope.EMAIL,
        ],
      });

      if (result) {
        const { identityToken } = result;
        const credential = OAuthCredential.fromJSON({
          providerId: 'apple.com',
          signInMethod: 'oauth',
          idToken: identityToken,
        });

        if (credential) {
          signInWithCredential(auth, credential)
            .then(() => {
              console.log('Apple sign in success');
            })
            .catch((error) => {
              console.log('Error:', error);
            });
        } else {
          console.log('Failed to create credential for Apple sign in');
        }
      }
    } catch (error) {
      console.log('Error:', error);
    }
  };

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, async (user) => {
      if (user) {
        const { uid, email, displayName } = user;
        console.log('uid:', uid);
        console.log('email:', email);
        console.log('displayName:', displayName);
      }
    });
    return () => {
      unsubscribe();
    };
  }, [auth]);

  return { signInWithApple };
};

export default useGetAppleAuth;

4. firebase에 애플 로그인 추가

 

가장 애를 많이 먹었던 부분입니다.

firebase Authentication 부분에서 로그인 제공업체를 추가한 뒤

서비스 ID를 다음과 설정해주셔야 합니다.

저희가 만든 서비스 ID가 아닌 

host.exp.Exponent를 설정해 줘야 제대로 동작합니다.

 

다른 값으로 설정하게 되면 다음과 같은 오류가 납니다.

Error: [FirebaseError: Firebase: The audience in ID Token [host.exp.Exponent] does not match the expected audience com.ww8007.pickly. (auth/invalid-credential).]

이게 찾아보니까 host.exp.Exponent 자체는 expo 기본 설정이고

개발자가 따로 건드릴 수 없는 값이라고 하네요.

expo-dev-client를 사용하여 다른 프로젝트 환경을 구성하여 문제를 해결할 수 있긴 하지만

이를 production 환경과 dev 환경을 다른 프로젝트를 가져갈 필요는 없으니

다음과 같이 설정해 주는 게 맘 편할 것 같습니다...

 

그러면 다음과 같이 정상적으로 애플 로그인이 동작하는 모습을 확인하실 수 있습니다.

애플 로그인


결과

이제 저희는 두 개의 OAuth를 사용할 수 있게 되었습니다.

OAuth에서 받아온 정보를 토대로 이제 사용자 인증을 하고 서버에 요청을 하는 일들만 남았네요!

React Native를 오랜만에 해보니 바뀐 부분들이 많고

이전에 사용하던 라이브러리들이 바뀌고 Expo Router에 대해서는 사용하면서 Next.js와 비슷하다는 생각이 많이 들었네요.

끝으로 지금 만들고 있는 프로젝트의 로그인 창을 남겨두고 글을 마무리하도록 하겠습니다 😃

피클리

profile

기록의 습관화

@ww8007

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!