[iOS] 애플 로그인 구현하기 (SSO)
아이폰 앱을 배포할때 맞닥뜨리는 장벽 중 하나가 바로 애플 로그인이다.
애플 이외에도 플랫폼 로그인 연동 서비스들은 많다.
구글, 페이스북, 네이버, 깃헙, 카카오, 등등...
하지만 그중에서도 가장 특별한 녀석을 꼽으라면 애플이 나올 것이다.
다른 서비스들은 써도 그만 안써도 그만이지만, 애플은 그 강제성 때문에 사용하는 경우가 잦기 때문이다.
좋은가?
서비스를 제공하는 입장에서는 전혀 좋지가 않다.
개발용 가이드 문서도 개판이요. 인증 시스템 자체도 짜증나고 번거롭게 되어있다.
관리도 개판으로 하는지 이상한 쓰레기 값도 잔뜩 주고.. 뭔지 모르겠다.
게다가 다른 서비스들은 이름이나 이메일 등의 다양한 정보를 받아와서 연동을 할 수 있는데, 애플은 가져올 수 있는게 거의 없다시피하다.
애플에서 사용자값을 가져올때 확실하게 받아올 수 있는 값은 오로지 그 사용자의 고유 ID 뿐이다!
32글자 16진수 문자열 양쪽에 10진수 하나씩 붙어있는 의미없는 값이다. 그냥 말 그대로 고유성만 체크할 수 있다.
이메일도 가져올 수 있기는 하지만, private email로 받아올 때도 잦고, 아예 안오기도 하더라.
그렇다고 전화번호나 이메일 같은 정보를 받으려고 가입프로세스에 정보 적는칸을 추가하면, 그런거 다 하지말라고 반려하더라. 뭐 어쩌자는 것이지..?
그럼 이걸 왜쓰는가?
아이폰 앱 심사할때 이걸로 딴지를 걸기 때문이다.
아이폰 앱을 배포할때 항상 애플로그인을 붙여야 하는 것은 아니다.
하지만 카카오나 구글 등의 다른 SSO를 사용한다면, 애플로그인을 붙여야만 한다.
그래서 그냥 일반 로그인만 구현해서 올리면 문제가 없지만, 만약 앱에 카카오 로그인만 붙여서 앱을 제출한다면 무조건 반려를 당한다.
애플의 짜증나는 깡패짓 중 하나다. 좀 맞아야하는데.
인증 프로세스
대충 이런식으로 프로세스가 진행될 것이다.
- 앱이나 브라우저에서 애플 계정으로 로그인을 한다.
- 그럼 애플에서 code라는 일회용 인증토큰을 준다. 한번만 써도 소멸하고, 수명은 5분이다.
- code를 서버에 보내서 서버가 유효한 애플사용자인지를 검증한다.
- 검증하고 나면 애플사용자에 대한 고유값을 받아올 수 있다. 그걸로 된 계정이 있다면 그걸로 로그인시켜주고, 없으면 가입시킨다.
여기서 토큰은 한번씩밖에 쓰지 못하므로, 로그인만 토큰을 받아서 appleID를 반환해주고, 회원가입에서는 토큰을 받지 않고 appleID만 받는 식으로 구현했다.
세팅
애플 개발자 계정에 들어가서 이래저래 추가하고 리다이렉트 URI도 깔아줘야 한다.
스크린샷은 나중에 다시 할일이 있다면 추가하겠다.
프론트측 처리 (브라우저)
브라우저에서 처리하는 방법은 그렇게 어렵다거나 할건 없다.
이거 추가해주고
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
이런식으로 써준다.
<html>
<head>
</head>
<body>
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
<script type="text/javascript">
AppleID.auth.init({
clientId : '[CLIENT_ID]',
scope : '[SCOPES]',
redirectURI : '[REDIRECT_URI]',
state : '[STATE]',
nonce : '[NONCE]',
usePopup : true
});
</script>
</body>
</html>
client id는 애플 개발자 관리 페이지에서 가져올 수 있고, redirect url은 애플 연동시에 어느 링크로 리다이렉트를 시켜줄 것인지를 정한다. 이 과정에서 리다이렉트 링크에 code 값을 넣어준다.
그걸 또 프론트에서 적절히 받아다가 서버에 넘겨주면 된다.
서버측 처리 (Node.js - Typescript)
예시 코드는 Typescript다.
키를 들고있다가 프론트에서 리다이렉트로 받은 code를 받아서 정보를 가져오면 된다.
import appleSignin from 'apple-signin-auth'
const privateKey = `-----BEGIN PRIVATE KEY-----
...키값...
-----END PRIVATE KEY-----`
export async function checkAppleCode(code: string) {
const clientSecret = appleSignin.getClientSecret({
clientID: '...', // Apple Client ID
teamID: '...', // Apple Developer Team ID.
privateKey: privateKey, // private key associated with your client ID. -- Or provide a `privateKeyPath` property instead.
keyIdentifier: '...', // identifier of the private key.
})
const options = {
clientID: '...', // Apple Client ID
redirectUri: '...', // use the same value which you passed to authorisation URL.
clientSecret: clientSecret,
}
try {
const tokenResponse = await appleSignin.getAuthorizationToken(
code,
options,
)
const idToken = tokenResponse?.id_token
if (!idToken) {
return null
}
// 받아온 id_token 값으로 원본 사용자 정보 획득! 한번만 사용 가능
const decoded = await appleSignin.verifyIdToken(idToken)
return { appleId: decoded?.sub, email: decoded?.email, decoded }
} catch (err) {
console.error(err)
return null
}
}
내용이나 설명이 많이 부실하다.
예전에 구현하면서 개발새발 썼던 것인데, 일단 올려놓고 나중에 다시 보완하려 한다.