현재 출시를 앞둔 서비스인 웹소설 유저를 위한 기록 & 커뮤니티 서비스 웹소소 는 안드로이드와 iOS 두 OS를 모두 지원하는데, 사용자들이 간편하게 서비스에 가입하고 이용할 수 있도록 소셜 로그인 기능을 도입하고자 했다.
이번 글에서는 애플 소셜 로그인 백엔드 부분을 구현하면서 겪었던 시행착오와 해결 과정을 공유하려고 한다!
2024년 3월 이후, iOS 앱이 타사 소셜 로그인 서비스를 이용하는 경우 필수였던 애플 소셜 로그인 요건이 해제되었지만, 여전히 데이터 수집 범위는 이메일 주소로 제한되어야 한다는 새로운 조건이 추가됨. - Apple 앱 심사지침 공식문서
애플의 정책 변화로 인해 기존에는 필수였던 애플 소셜 로그인 요건이 완화되었지만, 사용자 경험 향상을 위해 서비스에 애플 소셜 로그인 기능을 도입하기로 결정했다.
로컬 환경에서 테스트가 불가능하여, ngrok을 활용한 애플 소셜 로그인 작동 테스트
애플 소셜 유저가 탈퇴 시 해당 토큰을 어떻게 취소할지에 대한 문제
(탈퇴 직전 재로그인 처리 vs 유효기간이 없는 리프레시 토큰을 DB에 저장하여 관리)
자꾸 발생하는 client_id 오류
애플이 제공하는 소셜 로그인 REST API는 로컬 환경에서 테스트가 불가능하도록 설계되어 있다.
코드 구현은 완료했지만 로컬 환경에서 테스트할 수 없었기 때문에, 방법을 모색하던 중 외부 네트워크에서 로컬 환경으로 접근할 수 있는 터널링 프로그램인 ngrok을 알게 되었다. ngrok은 HTTPS로 연결할 수 있는 기능도 제공하기 때문에 이 문제를 해결하는 데 적합하다고 판단했다.
% brew install ngrok
위 명령어를 통해 ngrok을 설치한다.
로컬 환경에서 ngrok을 실행시키면 세션 유지 시간이 기본적으로 2시간으로 제한되기 때문에, 세션이 만료되면 명령어를 통해 포워딩을 다시 시작해야 한다.
이때, 다시 시작된 포워딩 URI가 변경되어 기존에 설정해 둔 경로를 사용할 수 없게 되므로, Redirect URI 값이 고정되어야 하는 애플 소셜 로그인에는 사용하기 어렵다.
다행히도, ngrok에서 회원가입을 하면 URI를 고정시킬 수 있는 기능을 제공한다.
회원가입 후 아래 명령어를 터미널에 입력하여 고정된 URI를 사용할 수 있다.
이제 아래 명령어로 ngrok을 실행시켜주면 끝이다!
% ngrok http localhost:8080
ngrok을 실행하면 위와 같은 화면이 나타나고, 애플 개발자 계정에 이 포워딩 주소를 이용하여 Redirect URI를 설정한 후 테스트를 진행하면 된다.
하단에는 어떤 요청이 들어왔고, 어떤 상태 코드를 반환했는지 실시간으로 기록된다.
(에러가 난게 찍혔다 하하)
ngrok의 자세한 사용법은 ngrok 공식문서에서 확인할 수 있다.
이 방법으로 애플 소셜 로그인 테스트를 마치고 1차 배포를 무사히 완료했다. 😃
두 번째로 문제가 되었던 부분이다.
애플 소셜 로그인을 통해 서비스에 가입한 사용자가 탈퇴를 원할 경우, 애플 서버에서 사용자의 연결을 끊는 과정이 필요하다. 이는 애플에서 제공하는 (공식문서)에 설명되어 있다.
이 과정에서 보이는 것처럼, token
값이 필요하다.
이 token
값은 사용자가 로그인할 때 발급받을 수 있는 정보이며, 토큰의 종류는 총 두 가지로 나뉜다.
access_token
refresh_token
이다.처음 구현 방식에서는 사용자가 탈퇴 직전에 클라이언트 측에서 재로그인을 통해 access_token
과 refresh_token
을 다시 발급받고, 서버가 이 정보를 받아 애플 서버에 토큰 취소 요청을 보내도록 했다.
이 방식 자체에는 문제가 없었으나, 클라이언트 측에서 플로우가 다소 불편한 부분이 있었고, 사용자가 탈퇴하려면 재로그인하는 부분이 어색하게 느껴질 수 있었다.
이에 따라, 사용자가 탈퇴 직전에 재로그인하지 않고, 최초 로그인 시 발급받은 정보를 저장해 두었다가 탈퇴 시 사용하는 것이 더 나을 것이라는 제안을 받았다.
하지만, 아래와 같은 우려가 따라왔다.
'탈퇴할지 모르는 사용자의 탈퇴를 위한 정보를 데이터베이스에 저장해 둔다는 것이 과연 적절한가? 이는 성능 저하를 불러오지 않을까?'
그러나 Apple 토큰의 값은 JWT 형식의 일반 문자열이다. 이러한 토큰 정보를 사용자마다 하나씩 저장한다고 해서 성능에 미치는 영향은 매우 미미할 것이라고 판단했고, 서비스 자체가 아주 많은 고객을 거느리고 있지 않기 때문에 성능 우려는 크지 않았다.
또한, 새로운 방식의 경우 처음 로그인 시 발급받은 refresh_token
은 만료 기간이 없고, 이 토큰을 사용해 탈퇴를 처리할 수 있어 재로그인 및 추가적인 토큰 발급 과정이 필요 없다는 점에서 훨씬 간편하다는 이점이 있었다. 이러한 이유로 새로운 방식을 채택하기로 결정했다.
따라서 애플 사용자 탈퇴 로직은 아래와 같이 최종적으로 선정했다.
- 탈퇴 API 호출
- DB에서 해당 사용자의 Apple
refresh_token
값 조회- Apple 서버에
refresh_token
으로 해당 사용자 토큰 취소 요청- DB에서 사용자 삭제
애플 서버에 소셜 로그인 요청을 보낼 때, 500 에러가 발생하여 로그를 확인해본 결과, 아래와 같은 에러 메시지가 나타났다.
400 Bad Request: {"error":"invalid_grant","error_description":"client_id mismatch. The code was not issued to {client_id값}."}
해당 에러는 토큰 발급 요청 시 전달된 client_id 값이 애플 서버에서 기대하는 값과 일치하지 않는 경우 발생한다.
문제를 확인해본 결과, 애플 로그인에서 client_id 값은 특정 상황에 따라 서로 다른 두 가지 ID를 사용해야 하며, 이를 잘못 지정한 것이 원인이었다.
애플 로그인을 구현할 때, 아래와 같이 App IDs와 Service IDs라는 두 가지 ID를 생성하게 된다.
이 두 ID는 로그인 방식에 따라 다르게 사용해야 하고, 잘못된 ID를 사용하면 인증 요청이 실패하게 된다.
App IDs
사용 시점: iOS 앱 내에서 로그인 연동을 진행하는 경우.
설명: iOS 앱의 Bundle ID를 기반으로 생성되며, 애플 앱 생태계에서 인증 요청을 처리할 때 사용된다.
Service IDs
사용 시점: 웹사이트 또는 웹뷰 환경에서 로그인 연동을 진행하는 경우.
설명: 웹 기반 서비스에서 애플 로그인을 처리하기 위해 별도로 생성한 ID로, 애플 Developer Console에서 설정한 Service ID와 일치해야 한다.
우리 서비스에서는 앱 내부에서 로그인을 진행하고 있었지만, 잘못된 ID(Service IDs)를 client_id로 전달하고 있었다. 이를 앱 환경에 맞는 App IDs로 변경한 후, 애플 서버와의 인증이 정상적으로 이루어졌다!
애플 소셜 로그인은 다른 소셜 로그인보다 더 까다로운 점이 많아 처음 도입할 때 시행착오를 많이 겪었다. 특히 테스트 환경의 제약이나 탈퇴 토큰 관리 같은 부분은 예상치 못했던 도전 과제였다.
이번 글을 통해 내가 겪은 문제와 해결 과정을 공유하면서, 비슷한 어려움을 겪고 있는 사람들에게 조금이라도 도움이 되었으면 한다. 😊