React Native 애플 로그인에서 탈퇴 기능 구현
1. 서두
토이 프로젝트에서 아래 라이브러리를 사용해 소셜 로그인을 구현하고 있다.
- @react-native-firebase/app: React Native Firebase 코어 모듈
- @react-native-firebase/auth: React Native Firebase Authentication 모듈
- @react-native-google-signin/google-signin: React Native 구글 소셜 로그인 라이브러리
- @invertase/react-native-apple-authentication: React Native 애플 소셜 로그인 라이브러리
이 글에서는 애플 소셜 로그인에서도 탈퇴(앱과 연결 끊기) 기능 구현을 정리한다. 탈퇴는 사용자에게 당연히 제공되어야 하는 사용자의 권리다. 뭐 필수 기능이니 구현하는 데 어려울 건 없을 것이다. 아마 라이브러리에 탈퇴하기()
같은 메서드가 있을 것이고 우리는 그걸 호출하기만 하면 될 것이다. 아주 쉽다. 자 시작해보자. ...어? 아니네?
1.1. 엥? 로그인은? 로그아웃은? 구글은?
애플 소셜 로그인/로그아웃, 구글 소셜 로그인/로그아웃/탈퇴 기능 구현에는 특별한 이슈가 없다. 개발자가 상상하고 있는 거의 그대로 메서드가 나와있고 우리는 호출하기만 되는 형태다. 일부 콜백을 사용해야 하긴 하지만 큰 문제는 아니다. 따라서 일단은 이슈가 있다고 생각되는 애플 쪽의 탈퇴 기능을 먼저 정리한다. (나머지 기능들은 나중에 정리할 수도 있다.) 일단은 공식문서들을 참고하시라.
- React Native Firebase - Authentication
- Github - react-native-google-signin/google-signin
- GitHub - invertase/react-native-apple-authentication
2. 구현
2.1. onCredentialRevoked()
일단 @invertase/react-native-apple-authentication 라이브러리의 README 를 찬찬히 살펴봐도 탈퇴를 위한 메서드는 존재하지 않는다. (구글 쪽 라이브러리에서는 revokeAccess()
라는 메서드를 제공하는 것과 대조적이다.) 그나마 탈퇴 쪽과 관련된 메서드라면 onCredentialRevoked(listener)
가 있다. 이 메서드는 사용자가 탈퇴되었을 때 실행되는 콜백을 등록하게 해준다.
여기서 평소 iOS 를 사용하지 않는 사람들은 당황할 수 있다 (내가 그랬다). 탈퇴 기능은 제공하지 않지만 탈퇴 상태를 들을 수 있는 이벤트 리스너만 제공하고 있는 것이다. 그럼 대체 탈퇴는 어떻게 하는 거야?
다행히 답은 멀리 있지 않다. 애플은 iOS 기기 내에서 특정 앱과의 연결을 끊을 수 있는 (탈퇴할 수 있는) 기능을 제공한다. (apple.com 에서도 제공하는 것으로 알고 있다. 확인해보지는 않았다.)
iOS 기기의 [설정] 앱 - 최상단의 자신의 이름 영역 선택 - [암호 및 보안] - [Apple ID를 사용하는 앱] - 탈퇴할 앱 선택 - [Apple ID 사용 중단]
이 말은 즉슨, 탈퇴 기능을 직접 구현할 필요는 없다는 것이다. 우리는 사용자가 애플을 통해 탈퇴를 했을 때 그에 대응하는 처리만 해주면 된다.
구현 예
그럼 문서에 나와있는대로 탈퇴 기능을 구현해보자.
function App() {
// ...
useEffect(() => {
// 현재 기기가 애플 로그인을 지원하는 기기인지 확인
if(!appleAuth.isSupported) {
return;
}
const unsubscriber = appleAuth.onCredentialRevoked(() => {
// 사용자의 정보를 가지고 탈퇴 기능을 수행하자.
doSomethingForRevoke();
// firebase 에서도 로그아웃
auth().signOut();
});
return unsubscriber;
}, []);
// ...
return (
<View>
</View>
)
}
});
2.2. getCredentialStateForUser()
좋다. 구현이 완료되었다. 라이브러리의 README 에는 예외 처리에 대한 안내가 없는 걸로 봐서 이 콜백은 사용자의 탈퇴 시 무조건 실행을 보장하는 것 같다 (API 문서를 보고 싶지만 링크가 깨져있다).
그렇게 믿고 싶다. 하지만 세상에 백퍼센트는 없다. 특히 앱 프로세스가 완전히 죽은 상태에서 탈퇴를 하고 앱을 실행했을 때 onCredentialRevoked()
가 실행되지 않는 것을 여러차례 직접 목격한 나로서는, 더더욱 무시할 수 없었다. 이 콜백이 실행되지 않을 때를 대비해야 한다.
이럴 때 쓸 수 있는 메서드가 getCredentialStateForUser(user)
다. 이 메서드는 현재 사용자의 상태를 반환한다.
enum AppleCredentialState {
REVOKED = 0, // The Opaque user ID was revoked by the user.
AUTHORIZED = 1, // The Opaque user ID is in good state.
NOT_FOUND = 2, // The Opaque user ID was not found.
TRANSFERRED = 3, // N/A
}
즉 사용자가 앱에 진앱했을 때, 혹은 사용자 정보가 업데이트되었다고 추정될 때, 이 메서드로 사용자의 상태를 확인하면 탈퇴 여부를 확인할 수 있다는 말이다.
구현 예
여기서는 "사용자의 인증 정보가 바뀐 시점"을 React Native Firebase 의 auth().onAuthStateChanged()
콜백으로 확인한다. 만약 React Native Firebase 를 사용하지 않는다면 다른 방법으로 해당 시점을 찾아야 할 것이다.
function App() {
// ...
useEffect(() => {
const subscribe = auth().onAuthStateChanged(async user => {
if(!user) {
// 로그아웃된 상태 처리
loggedOut();
return;
}
const isApple = (
appleAuth.isSupported
&& user.providerData[0].providerId === 'apple.com'
);
const uidInProvider = user.providerData[0].uid;
const appleState = await appleAuth.getCredentialStateForUser(uidInProvider);
if(isApple && appleState === appleAuth.State.REVOKED) {
// 사용자의 정보를 가지고 탈퇴 기능을 수행하자.
revokeThisService();
// firebase 에서도 로그아웃
auth().signOut();
}
})
}, []);
// ...
return (
<View>
</View>
)
}
});
3. 결론
마지막으로 요약하자. React Native 에서 @invertase/react-native-apple-authentication 라이브러리를 사용해 탈퇴 기능을 구현할 때는 아래 두 개의 메서드를 적절히 잘 조합하면 되겠다.
onCredentialRevoked()
getCredentialStateForUser()