👨‍💻 프로그래밍/📦 Backend

애플 로그인, Server-to-Server Event 대응하기!

by 개발자 진개미 2025. 12. 26.
반응형


하려는 것

25년 10월쯤에 Apple에서 이메일이 왔습니다. 내용은 아래와 같았는데요!

 

 

New requirement for apps using Sign in with Apple for account creation - Latest News - Apple Developer

Starting January 1, 2026, developers based in the Republic of Korea must provide a server‑to‑server notification endpoint when registering a new Services ID, or updating an existing Services ID, to associate their website with an app using Sign in wi

developer.apple.com

 

내용을 요약하자면 2026년부터 한국에서 Apple 로그인을 사용하고 있는 경우 애플 계정의 변화 이벤트를 받을 수 있는 API를 만들어서 이벤트를 받고, 이에 따라 적절히 처리해야 한다고 합니다.

제가 운영하고 있는 사이트에서는 애플을 포함해서 구글, 카카오, 네이버, Passkey의 로그인 방식을 지원하고 있는데요...!

 

여기서 애플로 로그인을 선택했을 때 그 해당 유저의 애플 계정에 변화가 생기면 애플이 제 서버의 API를 호출해서 알려준다는 내용입니다. 찾아본 봐로는 이벤트는 크게 4가지가 있습니다.

  1. 유저가 이메일 수신 허용
  2. 유저가 이메일 수신 거부
  3. 유저가 Apple ID 연동 해제
  4. 유저가 Apple ID 삭제

요 각각의 이벤트에 대해 적절히 처리를 해 주면 끝납니다. 

제가 운영하고 있는 웹사이트 같은 경우는 이메일을 발송하고 있지 않아 1/2번은 할게 없이 로그만 남겨 두면 될 거 같고, 3/4번은 애플 연동을 해제하거나 계정을 삭제해야 할 듯싶습니다.


내 API Endpoint 애플에 등록하기

우선 애플 계정 관련 변화가 일어났을 때 어떤 API로 이벤트를 받을지를 지정해 줘야 합니다. 이건 개발자 포털에서 처리할 수 있습니다.

🐜 1 - Identities 항목에 가서 내 웹 사이트에 해당하는 Identity를 선택한다

https://developer.apple.com/account/resources/identifiers/list

 

🐜 2 - Sign in with Apple을 활성화하고 편집 버튼을 누른다

 

🐜 3 - 내 API를 등록한다

API는 내가 원하는 주소 아무거나 할 수 있습니다. POST로 호출한다는 것만 주의하면 됩니다.


Request를 보자...

다음으로 애플이 보내는 요청의 DTO 형식을 알아야 합니다. 이런 중요한 정보는 당연히 문서에 잘 나와 있을 줄 알았는데 아무리 찾아도 없어서 여러 자료를 본 결과 WWDC의 동영상에서 소개하고 있었습니다...

 

Get the most out of Sign in with Apple - WWDC20 - Videos - Apple Developer

Sign in with Apple makes it easy for people to sign in to your apps and websites with the Apple ID they already have. Fully integrate...

developer.apple.com

 

이벤트가 발생했을 때 보내지는 HTTP Body는 아래와 같습니다. 동영상의 13분경을 캡처한 내역입니다.

 

하지만 사실 이는 Decoding을 한 내역이고, 실제로는 payload에 JWT Token이 온다고 합니다.

{"payload": "JWT_TOKEN"}

JWT 유효성 검사를 해야 할까?

여기서 정석적으로 한다면 JWT Token을 이벤트로 받으면 이걸 Parsing 하기 전에 Apple의 Public Key로 유효성 검사를 해야 합니다. 하지만 저는 이 과정은 건너뛰기로 했습니다. 이유는 크게 3가지입니다.

  1. Server-to-server라 Endpoint를 알기부터 쉽지 않음
  2. 요청을 보내려면 유저의 애플 계정 내부 PK 값을 알아야 하는데 이걸 알 수 없음
  3. 설령 가짜 요청을 보내더라도 최악의 경우 애플 계정이 연결 해지 되는 것뿐

물론 실제 회사라면 유효성 검사를 해야겠지만 여기서는 너무 과한 스펙이라도 판단해 과감하게 건너뛰었습니다.


테스트는 어떻게...?

모든 개발은 테스트를 하고 배포를 해야 끝납니다. 이건 어떻게 테스트를 해야 할까요?

우선 저는 최대한 제가 맞다고 생각하는 방향으로 개발을 진행하고 배포를 했습니다. 그리고 제 애플 계정에 가서 이메일 수신 거부를 했습니다. 이제 제 애플 계정 상태가 바뀌었으니 애플이 제 애플 계정에 대한 이벤트를 보내 줄 거고, 로그를 철저하게 남겼기 때문에 문제가 일어나면 디버깅을 할 수 있습니다.


Kotlin 코드

DTO는 아래와 같이 만들었습니다.

data class RawRequest(
    val payload: String,
)

data class ParsedRequest(
    val iss: String, // `https://appleid.apple.com/`으로 고정
    val aud: String, // Bundle Identifier
    val iat: Long,
    val jti: String, // Unique Events Stream ID
    val events: Event,
) {
    data class Event(
        val type: String,
        val sub: String, // USER ID
        val eventTime: Long,
    ) {
        enum class Type(
            val displayName: String,
        ) {
            EMAIL_DISABLED("유저가 이메일 수신 중단"),
            EMAIL_ENABLED("유저가 이메일 수신 활성화 함"),
            CONSENT_REVOKED("유저가 Apple ID 연동 해제함"),
            ACCOUNT_DELETE("유저가 Apple ID 삭제함"),
        }
    }

    val eventType: Type? get() = when (events.type.uppercase()) {
        "EMAIL-ENABLED" -> Type.EMAIL_ENABLED
        "EMAIL-DISABLED" -> Type.EMAIL_DISABLED
        "CONSENT-REVOKED" -> Type.CONSENT_REVOKED
        "ACCOUNT-DELETE" -> Type.ACCOUNT_DELETE
        else -> null
    }

    val oauthAppleId: String get() = events.sub
}

저는 DTO를 만들 때 되도록이면 Namescope를 제한하기 위해 Nested 하게 만들고, 이 객체의 내부 정보는 Computed Variable로 처리합니다. 그리고 각 Property에 주석을 꼭 남겨 둡니다. 많은 경우 Property의 이름만으로는 역할을 추정하기 충분하지 않기 때문에...

 

API는 Spring Boot를 사용해 만들었습니다.

@PostMapping("/v1/oauth2/apple/server-events")
fun handleAppleOauth2ServerEvents(
    @RequestBody request: RawRequest,
)

참고

 

애플로 로그인, 서버로 Apple ID 연동 해제 알림 받기

요즘 회원가입 프로세스 간편화의 일환으로 소셜 로그인을 붙이고 있다. 대상은 애플과 카카오. 왜 갑자기 구글도 아닌 애플인가 싶었지만, 알고보니 올 4월부터 소셜 로그인 기능을 제공할 경

velog.io


반응형