구글 로그인만 붙여서 앱을 올렸다가 심사에서 리젝을 먹었다. Apple의 App Store 가이드라인 4.8 때문이다. 서드파티 소셜 로그인(구글, 카카오 등)을 제공하는 앱은 iOS에서 "Sign in with Apple"도 같이 제공해야 한다. 안 넣으면 그냥 반려다.
다행히 Expo에선 expo-apple-authentication로 금방 붙는다. 네이티브 버튼까지 제공해줘서 가이드라인에서 요구하는 디자인도 알아서 맞는다.
설치와 설정
npx expo install expo-apple-authentication
app.json에 플러그인을 넣고 iOS 엔타이틀먼트를 켜준다.
{
"expo": {
"ios": { "usesAppleSignIn": true },
"plugins": ["expo-apple-authentication"]
}
}
이 기능은 iOS 전용이고 Expo Go에선 안 돌아간다. npx expo prebuild 후 dev client로 빌드해야 실제로 동작한다.
버튼과 로그인 처리
버튼은 라이브러리가 주는 네이티브 컴포넌트를 쓰는 게 안전하다. 색/모양을 직접 그리면 가이드라인 위반이 될 수 있다.
import * as AppleAuthentication from 'expo-apple-authentication';
import { Platform } from 'react-native';
export function AppleSignInButton() {
// Android에선 숨긴다
if (Platform.OS !== 'ios') return null;
return (
<AppleAuthentication.AppleAuthenticationButton
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
cornerRadius={8}
style={{ width: 240, height: 48 }}
onPress={async () => {
try {
const credential = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL,
],
});
// 이 토큰을 서버로 보내 검증 + 세션 발급
console.log(credential.identityToken);
} catch (e: any) {
if (e.code === 'ERR_REQUEST_CANCELED') return; // 사용자가 취소
throw e;
}
}}
/>
);
}
가장 중요한 함정 — 이름·이메일은 딱 한 번만 온다
여기서 제일 많이 당한다. fullName과 email은 최초 로그인 때 한 번만 내려온다. 같은 기기에서 두 번째부터 로그인하면 이 값들이 null로 온다. 항상 오는 건 credential.user(안정적인 사용자 ID)와 identityToken 정도다.
그래서 처음 받은 순간에 이름/이메일을 서버에 저장해둬야 한다. "나중에 또 받으면 되지" 하고 넘기면, 테스트 중에 지웠다가 다시 로그인하면 이름이 안 오니까 당황하게 된다. (잘못 저장했다면 설정 → Apple ID → 암호 및 보안 → Apple로 로그인에서 앱을 지우면 다음 로그인 때 다시 최초로 취급된다.)
검증은 서버에서 identityToken을 Apple 공개키로 검사하면 된다. 클라이언트가 보낸 user 값만 믿지 말고 토큰을 꼭 검증하자.
마무리
정리하면 세 가지만 기억하면 된다. iOS에서만 노출하고, 네이티브 버튼을 그대로 쓰고, 이름·이메일은 첫 로그인에 받아서 바로 저장한다. 심사 리젝 피하려고 억지로 넣는 기능이지만, 생각보다 깔끔하게 붙어서 30분이면 끝났다.