Expo로 OAuth를 구현해보자!

김지민·2022년 5월 4일
16
post-thumbnail

| 노잉(knowing)이라는 프로젝트를 진행한 내용을 바탕으로 다른 사람들은 Expo로 Oauth를 구현하며, 삽질을 하지 않았으면 하는 바람에 글을 써본다.

OAuth를 왜 쓸까?

OAuth는 다른 서비스의 회원 정보를 안전하게 사용하기 위한 방법이다.
고객이 자신의 Google, Kakao, 네이버 등의 아이디/비밀번호를 우리 서비스에 알려주지 않더라도, 고객의 정보를 우리 서비스에서 안전하게 사용하기 위한 방법이다.

OAuth의 동작과정!

다음은 내가 만든 서비스의 오어쓰 동작과정이다.

  1. 우리 서비스에서 로그인을 누르면 각 플랫폼의 인증페이지로 넘어간다.
  2. 인증이 성공할 경우 링크로 보내준 redirect_uri로 코드와 함께 이동한다.
  3. 전달받은 코드를 우리 서비스 서버로 보내준다!
  4. 서버에서는 구글에게 코드를 전달해주고, 코드 안에있는 유저정보를 가져온다.
  5. 유저정보를 가지고있는 access_token을 다시 클라이언트로 준다!

대부분의 오어쓰는 이러한 과정으로 동작한다.

Expo Setting

우리가 Expo에서 OAuth를 사용하기 위해서는 각 플랫폼(구글, 네이버, 애플 등)에서 애플리케이션을 등록해줘야 한다. 그러기 위해서는 expo 프로젝트안에서 bundle id를 설정해줘야한다.
app.json

{
	"ios":
		"bundleIdentifier": "your bundle id",
	"android":
		"package": "your bundle id"
}

또한 Android의 경우 sha-1 인증서 디지털 지문이 필요한 플랫폼도 있다.

이러한 경우에는 당황하지 말고, 터미널을 킨 후, 자신의 Expo프로젝트로 이동하여

expo fetch:android:hashes

를 입력한다. 그러면 sha-1 인증서 디지털 지문을 구할 수 있다.

Expo Get Redirect Uri

Expo에서 RedirectUri를 얻는 방법은 2가지 정도가 있다.
1. 직접 redirect Uri를 만든다.
2. expo-auth-session을 통해 가져온다.

먼저 첫번째 방법을 사용한다면 app.json에 있는 slug와 자신이 로그인한 expo계정을 사용하여 만들 수 있다.
우리가 만든 Expo 프로젝트의 redirect uri는 https://auth.expo.io/@계정이름/slug가 된다.
또한 expo에 로그인 하는 방법은 expo cli를 다운받은뒤 expo login -u username -p password로 로그인하면 된다.

두번째 방법은 expo-auth-session에 getRedirectUrl을 사용한다.

import * as AuthSession from 'expo-auth-session';
const url = AuthSession.getRedirectUrl();

메게변수에 문자열을 넣는다면 "https://auth.expo.io/@계정이름/slug/문자열"식으로 나오게 된다.

Apple OAuth

오어스 중 그나마 쉬웠다고 생각했던 애플 OAuth에 대해 소개하겠다. Apple OAuth를 넣었던 이유는 OAuth를 사용하고 App Store에 올리기 위해서는 무조건 Apple로그인이 필요했기 때문이다.

Expo에서 Apple Login을 하기 위해서는 "expo-apple-authentication"을 사용했다.
이 라이브러리는 iOS에서만 동작하기 때문에 안드로이드에서는 사용할 수 없다.
공식문서: https://docs.expo.dev/versions/latest/sdk/apple-authentication/


위와 같이 애플로그인은 버튼 Component를 주며, 안에 각종 옵션들이 들어있다.
아래와 같은 대표적인 옵션이 있다.

  • onPress: 버튼을 눌렀을 경우 실행하는 함수를 넣는다.
  • buttonType: 문구를 "Sign In with Apple"나 "Continue with Apple" 중 선택할 수 있다.
  • buttonStyle: 버튼의 색깔을 선택할 수 있다.(BLACK, WHITE, WHITE_OUTLINE)

이제 로그인을 하기위해서 signInAsync라는 함수를 써야한다.

import * as AppleAuthentication from "expo-apple-authentication";

const credential = await AppleAuthentication.signInAsync({
              requestedScopes: [
                AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
                AppleAuthentication.AppleAuthenticationScope.EMAIL,
              ],
            });

으로 유저 정보들을 가져올 수 있다. 또한, Apple은 보안 정책상 처음 로그인 할 경우에만 유저 정보를 준다.

Naver OAuth

네이버 로그인은 expo-auth-session으로 구현했다.
expo-auth-session은 expo에서 각종 OAuth를 웹뷰 형식으로 처리해주는 라이브러리이다.
공식문서: https://docs.expo.dev/versions/v44.0.0/sdk/auth-session/

다음과 같은 방식으로 expo-auth-session을 사용할 수 있다.

const naverLogin = async () => {
    const result = await AuthSession.startAsync({
      authUrl: "https://nid.naver.com/oauth2.0/authorize?response_type=원하는 반환 형식&client_id=yourClientId&redirect_uri=yourExpoUri",
    });

    if (result.type === "success") {
      const code = result.params.code;
      mutate({
        id_token: code,
        provider: "NAVER",
      });
    }
  };

여기서 response_type은 code나 idToken등이 있다. 또한, client_id는 아까 위에서 말했듯이 애플리케이션 등록을 한 뒤 얻은 client_id를 사용하면 된다. rediect_uri또한 위에서 구한 redirect_uri를 사용하면된다.

Google OAuth

내가 느끼기에 가장 힘들었던 것 같다. 우선 구글은 2016년부터 더나은 사용성과 보안성을 위해 웹뷰에서의 OAuth사용을 제한했다. 그렇기 때문에 웹뷰로 구글 OAuth를 구현하는 것은 어려워졌다... ㅜㅜ
구글 OAuth를 위한 라이브러리는 expo-google-sign-in, expo-auth-session/providers/google가 있었는데, 각각의 라이브러리에 문제점이 있다.

  • expo-google-sign-in: 개발중에는 이 라이브러리 사용이 불가능하지만, 배포(standalone)를 할때에는 사용할 수 있다.
  • expo-auth-session/providers/google: 개발중에는 잘 동작하지만, 배포(standalone)를 하면 400(redirect_mismatch)가 나면서 동작하지 않는다.

나는 2번째 라이브러리를 사용한 뒤 배포 후 동작하지않아 많은 삽질을 했다...
그렇기 때문에 각자의 프로젝트에 맞게 라이브러리를 사용해야 한다.

expo-google-sign-in

expo-google-sign-in은 배포 후에만 사용가능하다. 또한 expo-auth-session을 사용하며, 더이상 사용되지 않는다고 하지만, expo-auth-session은 배포후 동작되지 않았기 때문에 어쩔 수 없이 사용했다.
공식문서: https://docs.expo.dev/versions/latest/sdk/google-sign-in/

사용법

import * as GoogleSignIn from "expo-google-sign-in";
//구글 로그인 설정
await GoogleSignIn.initAsync({
        signInType: GoogleSignIn.TYPES.DEFAULT,
        clientId:
          Platform.OS === "android"
            ? env.googleClientId.androidId
            : env.googleClientId.iosId,
        scopes: [
          GoogleSignIn.SCOPES.OPEN_ID,
          GoogleSignIn.SCOPES.EMAIL,
          GoogleSignIn.SCOPES.PROFILE,
        ],
      });
      //사용자가 Play 서비스가 아직 최신 상태가 아닌 경우 Play 서비스를 업데이트할 수 있는 모달 제공
      await GoogleSignIn.askForPlayServicesAsync();
      //구글 로그인으로 이동 및 response 반환
      const response = await GoogleSignIn.signInAsync({});

expo-auth-session/providers/google

이 라이브러리가 expo에서 사용하라고 하는 방법이다. 그렇지만 개발 중에만 사용가능하며, 배포후에는 에러가 나오게된다.
공식문서: https://docs.expo.dev/versions/latest/sdk/auth-session/#google

사용법

import * as Google from 'expo-auth-session/providers/google';

const [request, response, promptAsync] = Google.useAuthRequest({
	expoClientId: 빌드하기 전 사용할 Client_id,
    iosClientId: ios client_id,
    androidClientId: android client_id,
    webClientId: web Client_id,
    redirectUri: redirecUri,
    scopes: [가져올 유저정보],
    responseType: code나 idToken등 가져오고 싶은 타입,
    )}

const googleLogin = () => {
	promptAsync();
}

끝마치며

이렇게 expo로 여러 플랫폼의 OAtuh를 해보았는데, 처음에는 만만하게 봤다가 된통 당한 것 같다...
그렇기 때문에 다른사람은 나처럼 삽질을 하기보다는 이 글을 읽고 좀 더 편하게 OAuth를 구현하면 좋겠다.
또한, 반응이 좋으면 expo를 사용하면서 어려웠던 다른 부분들도 올릴까한다..

궁금한 점이 있거나 수정해야 하는 부분이 있으면 언제든 연락주세요!!
이메일 jm004471@gmail.com

1개의 댓글

comment-user-thumbnail
2024년 8월 27일

이렇게 하면 백엔드 서버 없이 소셜 로그인을 구현할 수 있는건가요 ?

답글 달기