[#163] feat. 애플 네이티브 로그인 (App Store 심사 요건 4.8) - #164
Merged
Merged
Conversation
iOS 앱은 카카오 로그인을 제공하는 이상 애플 로그인도 함께 내야 한다. 애플은 카카오와 흐름이 다르다 — 앱이 주는 건 액세스 토큰이 아니라 ID 토큰(JWT)이고, 사용자 정보 API가 없어 서명 검증이 곧 인증이며, 이름은 최초 인가 1회만 클라이언트에 간다. 기존 OAuthClient(인가 URL/코드 교환/userinfo)에 끼우면 세 메서드 중 둘이 미지원이 되므로 네이티브 인증을 NativeSocialAuthenticator 로 분리했다. - POST /api/v1/users/social-login/apple/native — 응답은 카카오 네이티브와 동일 스키마. - AppleIdTokenVerifier: JWKS 서명 + iss·aud·exp 검증, rawNonce 를 주면 nonce 까지 대조. 공개키는 TTL 캐시를 두되 모르는 kid 가 오면 한 번 다시 받아온다(애플 키 교체 대응). - 인가 코드 교환은 하지 않는다 — 검증에 필요한 건 공개된 번들 ID 뿐이라 새 비밀값이 없다. - 회원 생성·제재 판정·토큰 발급은 카카오와 같은 OAuthFacade 경로를 쓴다. - 카카오 계정과 잇지 않는다(제공자별 별도 회원). 이메일 병합은 애플 릴레이 주소와 계정 탈취 위험 때문에 택하지 않았다. 배경: ADR 0022. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
FE 연동 가이드를 위키에 올렸습니다 → Frontend-Apple-Login-Guide 앱이 챙겨야 할 것 세 가지(이름은 최초 1회만 온다 / rawNonce 권장 / authorizationCode는 보낼 필요 없음)와, 카카오 계정과 이어지지 않는다는 점의 화면 안내를 정리했습니다. |
SonarCloud New Code 커버리지가 71.5%(기준 80%)로 게이트에 걸렸다. 새 클래스가 전부 infrastructure 모듈인데 검증은 api 통합 테스트로만 했다 — 모듈별 집계라 잡히지 않는다. - NativeSocialAuthenticatorTest(infrastructure): 카카오 위임, 애플 매핑(sub·이메일· 애플이 안 주는 값·최초 1회 이름·nonce 전달), Fake 인증기, 팩토리의 미등록 제공자. - AppleIdTokenVerifierTest: is_private_email 의 boolean·부재 분기와 sub 없는 토큰 거부. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AppleOAuthProperties 를 만들면서 yml 에 블록을 넣지 않았다. local·test 는 Fake 인증기를 쓰므로 테스트가 전부 통과했지만, prod 에서는 client-ids 가 빈 리스트라 모든 애플 토큰의 aud 검증이 실패했을 것이다 — 설정 누락이 클라이언트 오류(1002)처럼 보이는 상태였다. - application-oauth.yml 의 local·test / prod 두 프로파일에 apple 블록 추가. prod 는 APPLE_CLIENT_IDS 로 주입하고 기본값은 앱 번들 ID. - clientIds 가 비면 WarnException(1002) 이 아니라 ErrorException(INTERNAL_ERROR) 으로 올린다. 조용히 전부 거부되는 대신 서버 설정 문제로 드러나야 한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
설정 누락을 하나 고쳐서 푸시했습니다(
앞서 PR 본문에 "기본값이 pics.ditto.app 으로 들어가 있습니다"라고 적었는데, 이 커밋 전까지는 사실이 아니었습니다. 지금은 맞습니다. |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #163
iOS 앱을 App Store에 올리려면 심사 지침 4.8에 따라, 카카오 로그인을 제공하는 이상 Sign in with Apple도 함께 내야 합니다.
계약
응답과 refreshToken 쿠키는 카카오 네이티브 로그인과 완전히 동일합니다(
accessToken·signupRequired·sanctioned·sanctionCode·suspendedUntil).왜 인터페이스를 하나 더 만들었나
애플은 카카오와 흐름이 다릅니다.
GET /v2/user/me기존
OAuthClient(getAuthorizationUrl/getAccessToken/getUserInfo)에 애플을 끼우면 세 메서드 중 둘이 "지원하지 않음"이 됩니다. 그래서 네이티브 인증만NativeSocialAuthenticator로 분리했습니다 —OAuthClient는 카카오 웹 리다이렉트 전용으로 남고, 회원 생성·제재 판정·토큰 발급은 두 제공자가OAuthFacade에서 그대로 공유합니다.ID 토큰 검증 (
AppleIdTokenVerifier)사용자 정보 API가 없으니 검증이 곧 인증입니다. 다섯 가지를 봅니다:
iss=https://appleid.apple.comaud= 설정한 클라이언트 ID(네이티브는 앱 번들 IDpics.ditto.app) — 다른 앱에서 발급된 토큰을 막는 지점expnonce— 앱이rawNonce를 보냈을 때만, 애플에 넘긴 SHA-256 해시와 대조공개키는 6시간 TTL 캐시를 두되, 캐시에 없는
kid가 오면 한 번 다시 받아옵니다 — 애플이 서명 키를 교체한 직후의 정상 로그인을 실패로 만들지 않기 위해서입니다.운영 준비물: 없습니다
새 비밀값·키 파일이 하나도 필요 없습니다. 인가 코드 교환을 하지 않기 때문입니다(그걸 하려면
.p8키로 서명한 클라이언트 시크릿 JWT가 필요합니다). 검증에 쓰는 건 공개된 번들 ID뿐이고, 기본값이pics.ditto.app으로 들어가 있습니다. 웹(Services ID)이 붙으면APPLE_CLIENT_IDS에 콤마로 덧붙이면 됩니다.하지 않은 것
response_mode=form_post(POST 콜백)라 현재 GET 콜백 구조와 맞지 않습니다. 웹은 카카오 유지검증
./gradlew build check통과AppleIdTokenVerifierTest15케이스 — 실제 RSA 키로 토큰을 서명해 검증합니다: 정상 통과 3, 거부 5(다른 키 서명·발급자 위조·다른 앱 aud·만료·JWT 아님), nonce 3, 공개키 캐시 4(재사용·kid 교체 시 재조회·재조회해도 없으면 거부·TTL 만료)OAuthControllerTest— 애플 로그인(REST Docs)·identityToken누락 400·카카오와 별도 회원이 되는지OAuthFacadeTest— 신규 가입 시 이름 저장, 재로그인 때 이름 없어도 기존 값 유지, 제공자별 소셜 계정 분리docs/domains/auth.md·socialaccount.md🤖 Generated with Claude Code