React Native - apple 로그인

개요

2020년 04월부터 App Store에 등록하려는 App은 Apple 로그인을 빼먹을 수 없게 되었다.

React Native에서의 구현(Type-Script)

ios 디바이스에 설치되는 application에서 Apple 계정 로그인 기능을 구현하려면 아래의 라이브러리를 설치해야만 한다.

 

React Native Apple Authentication

https://github.com/invertase/react-native-apple-authentication

 

invertase/react-native-apple-authentication

A React Native library providing support for Apple Authentication on iOS. - invertase/react-native-apple-authentication

github.com

npm install @invertase/react-native-apple-authentication

 

ios 폴더로 들어가 해당 라이브러리의 ios용 pod 또한 설치해준다.

 

cd ios && pod install

 

해당 라이브러리의 공식 github에서 제공하는 기본 login process는 다음과 같다.

 

import appleAuth, {
  AppleAuthRequestOperation,
  AppleAuthRequestScope,
  AppleAuthCredentialState,
  AppleAuthError
} from '@invertase/react-native-apple-authentication';

async function onAppleButtonPress() {
  // performs login request
  const appleAuthRequestResponse = await appleAuth.performRequest({
    requestedOperation: AppleAuthRequestOperation.LOGIN,
    requestedScopes: [AppleAuthRequestScope.EMAIL, AppleAuthRequestScope.FULL_NAME],
  });

  // get current authentication state for user
  const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);

  // use credentialState response to ensure the user is authenticated
  if (credentialState === AppleAuthCredentialState.AUTHORIZED) {
    // user is authenticated
  }
}

 

에러를 catch 하고, 로그인이 확인(Authorized)됬을 때의 동작을 위해 아래와 같이 작성한다.

 

import appleAuth from '@invertase/react-native-apple-authentication';

// 2021년 01월 30일 수정되었습니다.
    const appleLogin = async() => {
        try {
            // performs login request
             const appleAuthRequestResponse = await appleAuth.performRequest({
               requestedOperation: appleAuth.Operation.LOGIN,
               requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
             });
           
             // get current authentication state for user
             const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
           
             // use credentialState response to ensure the user is authenticated
             if (credentialState === appleAuth.State.AUTHORIZED) {
               // user is authenticated
               	   console.log(appleAuthRequestResponse);
             }
           
           } catch (error) {
               if (error.code === appleAuth.Error.CANCELED) {
                   // login canceled
               } else {
                   // login error
               }
        }
    }

 

appleAuthRequestResponse 객체의 비구조화 할당(destructuring assignment)을 통해 identityToken, email, user을 선언한다. 주의해야할 점은 email값은 최초 한번의 로그인 때만 email을 반환하고, 이후로는 null 값을 반환한다는 것이다. identityToken 내부에 email에 대한 정보가 있으므로 걱정하지 않아도 된다. 또한, unique한 값이 필요하다면 user를 사용하면 된다.

 

 

identityToken은 Apple Login Token으로써 JWT(JASON Web Token) 기반이다. 이 identityToken안에 있는 정보는 https://jwt.io/ 에서 Decode하면 확인할 수 있다.

 

jwt을 decode 할 수 있는 라이브러리는 다음과 같다.

https://www.npmjs.com/package/jwt-decode

 

jwt-decode

Decode JWT tokens, mostly useful for browser applications.

www.npmjs.com

npm install jwt-decode

 

사용법은 아래와 같다.

 

import jwtDecode from 'jwt-decode';

const token = 'eyJ0eXAiO... /// jwt token';
const decoded = jwtDecode(token);
console.log(decoded);

/* prints:
 * { foo: "bar",
 *   exp: 1393286893,
 *   iat: 1393268893  }
 */

 

jwt decode 기능을 삽입하기 위해 우선 jwt의 구조를 interface로 선언해준다.

 

interface tokenType {
    aud: string,
    auth_time: number,
    c_hash: string,
    email: string,
    email_verified: string,
    exp: number,
    iat: number,
    is_private_email: string,
    iss: string,
    nonce: string,
    nonce_supported: boolean,
    sub: string
}

 

전체 코드는 다음과 같다.

 

import appleAuth from '@invertase/react-native-apple-authentication';
import jwtDecode from 'jwt-decode';

interface tokenType {
    aud: string,
    auth_time: number,
    c_hash: string,
    email: string,
    email_verified: string,
    exp: number,
    iat: number,
    is_private_email: string,
    iss: string,
    nonce: string,
    nonce_supported: boolean,
    sub: string
}

// 2021년 01월 30일 수정되었습니다.
    const appleLogin = async() => {
        try {
            // performs login request
             const appleAuthRequestResponse = await appleAuth.performRequest({
               requestedOperation: appleAuth.Operation.LOGIN,
               requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
             });
           
             // get current authentication state for user
             const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
           
             // use credentialState response to ensure the user is authenticated
             if (credentialState === appleAuth.State.AUTHORIZED) {
               // user is authenticated
                   const { identityToken, email, user } = appleAuthRequestResponse;
                   const decodedToken: tokenType = jwtDecode(identityToken!);
                   console.log('email_from_decodedToken', decodedToken.email);
                   console.log('email', email);
                   console.log('user', user);
             }
           
           } catch (error) {
               if (error.code === appleAuth.Error.CANCELED) {
                   // login canceled
               } else {
                   // login error
               }
        }
    }

에러 1. AuthorizationError 1000

App 실행 후 로그인을 시도해보면

AppleLogin Error: The operation couldn’t be completed. (com.apple.AuthenticationServices.AuthorizationError error 1000.)

라는 에러 문구를 만날 수 있다.

https://github.com/invertase/react-native-apple-authentication/issues/9

 

Auth failed with com.apple.AuthenticationServices.AuthorizationError error 1000 · Issue #9 · invertase/react-native-apple-auth

I'm testing this on a simulator with iOS 13.2.2 (Sign-in with Apple available) I get the Apple Sign-in button and the auth popup shows up perfectly. Upon entering password, I get the following ...

github.com

Xcode에서 프로젝트 .xcowrkspace를 열고 Capability를 눌러 Sign In with Apple을 추가한다.

 

또한 에뮬레이터에서는 정확한 동작이 되지 않는 경우가 있으므로, 실제 device 상에서 동작을 test하는 것을 추천한다.

에러 2. not supported device

Error: AppleAuth is not supported an the device. Currently Apple Authentication works on
iOS devices running iOS 13 or later. User 'AppleAuth.isSupported' to check device is supported
before calling any of the module methods

 

 

기타 + @privaterelay.appleid.com 이메일

Apple ID 로그인 시 "나의 이메일 공유하기" 와 "나의 이메일 가리기" 이렇게 두가지 옵션이 있다. "나의 이메일 가리기"를 선택하여 로그인을 진행한다면 위의 email에 자신의 고유한 이메일이 아닌@privaterelay.appleid.com 형태의 이메일이 반환된다.

이는 Apple의 https://support.apple.com/ko-kr/HT210425에서 더 자세한 내용을 참고하길 바란다.

기타 +로그인 재설정

developer의 입장에서 test 시 최초 한번만 email이 반환된다는 것 때문에 로그인을 재설정하고 싶을 때가 있다.

 

 

설정(Setting) → 애플 계정 → 암호 및 보안(Password & Security) → Apple ID를 사용하는 앱(Apps that use your Apple id) → 해당 App을 누른 뒤 Apple ID 사용 중단을 누르면 된다.

 

 

애플의 정책 변경으로 인해 구현해야 되는 것이 늘었다...제길

+ Recent posts