React 웹에 Sign in With Apple 도입하기

배준형·2023년 12월 1일
6

서문

Sign in With Apple(이하 애플 로그인)은 유저들이 애플 아이디를 사용하여 웹 서비스에 로그인 할 수 있게 해주는 기능이에요. 이 기능은 애플의 보안 및 개인정보 보호 기준을 준수하며, 사용자가 웹 서비스에 대한 신뢰도를 높여주는 것으로 알려져 있습니다.

현재 제가 속한 팀의 웹 서비스는 자체 로그인, 카카오톡 로그인, 구글 로그인의 세 가지 방식을 지원하고 있는데요. 서비스 어플의 iOS 앱 스토어의 심사 요건에 부합하기 위해 애플 로그인을 추가하려고 합니다. 애플 로그인을 웹에 도입하는 방법에 대해 자세히 살펴보겠습니다.


Sign in With Apple

image

https://developer.apple.com/sign-in-with-apple/

애플 로그인은 OAuth 2.0 프로토콜을 기반으로 동작하는 기능입니다. OAuth 2.0은 인터넷 사용자들이 비밀번호를 공유하지 않고, 자신의 계정 데이터에 대한 접근 권한을 제 3자에게 부여할 수 있게 해주는 개방형 표준입니다.

애플 로그인이 동작하는 방식을 간단하게 살펴보면 다음과 같습니다:

  1. 사용자가 애플 로그인 기능이 구현된 버튼(Sign in with Apple)을 클릭합니다.
  2. 애플은 사용자에게 자신의 애플 계정으로 로그인하도록 요청합니다.
  3. 사용자가 애플 계정으로 로그인하면, 애플은 사용자의 아이디와 이메일을 암호화하고 이 정보를 포함하는 ID 토큰을 생성합니다.
  4. 애플은 이 ID 토큰과 함께 사용자를 웹 사이트로 리디렉션(다시 보냅니다). 이 때, 리디렉션 URL에는 앞서 생성된 ID 토큰과 함께 state 값도 함께 전달됩니다. 이 state 값은 보안을 강화하기 위해 웹 사이트가 로그인 요청을 시작할 때 생성하며, 리디렉션 후에 웹 사이트는 이 값을 검증하여 요청이 변경되지 않았음을 확인합니다.
  5. 웹 사이트는 리디렉션 URL에서 ID 토큰을 추출하고, 이 토큰을 디코딩하여 사용자의 애플 아이디와 이메일을 가져옵니다. 이 정보를 바탕으로 웹 사이트는 사용자를 인증하고 세션을 생성합니다.

즉, 사용자는 자신의 애플 계정을 통해 웹 사이트에 로그인할 수 있게 되는 것입니다. 이 과정에서 웹 사이트는 사용자의 비밀번호를 전혀 알 수 없으며, 사용자의 애플 아이디와 이메일만을 알 수 있습니다. 이 방식은 사용자의 개인 정보를 보호하면서 편리한 로그인 방식을 제공하게 됩니다.


Apple Service ID 발급받기

애플 로그인을 구현하려면 먼저 인증서, 식별자를 사용하여 Apple Developer 계정에 Service ID와 Client ID, RedirectURI 등을 설정해야 하는데요. Apple Developer 계정을 통해 Sign in With Apple을 활성화 하면서 설정할 수 있어요.

  1. https://developer.apple.com/account/resources/ 페이지에 접속합니다.
  2. Apple Developer에 로그인 화면이 뜨면 Apple 계정으로 로그인 합니다.
  3. Certificates, Identifiers & Profiles 제목이 있는 페이지로 이동되면 아래 박스친 부분을 순서대로 클릭합니다. - Identifiers → App IDs → Service IDs → Identifiers 소제목 옆 + 버튼
    Untitled 1

  1. 아래 화면에서 Services IDs를 클릭한 후 순서대로 기입하여 Service IDs를 생성합니다.
    image

  1. 이후 생성된 Service IDs에서 이후 애플 로그인으로 전달해줄 Redirect URI를 작성해줍니다.

여기서 설정한 Identifier 값이 이후에 사용할 Client ID가 됩니다.


React 웹에 Sign in with Apple 구현하기

아래 내용은 developer.app.comConfiguring your webpage for sign in with apple 등의 문서들을 순서대로 참고하여 작성되었습니다.


index.html

<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>

최상단 HTML에 아래 스크립트를 삽입합니다. 저는 Next JS를 사용하고 있어서 _document.tsx 파일에 삽입해 주었습니다.


AppleLogin.tsx

const AppleLogin = () => {
  const loginWithApple = async (e) => {
    e.preventDefault();

    console.log('sign in with apple');

    window.AppleID.auth.init({
      clientId: '[CLIENT_ID]',
      scope: '[SCOPES]',
      redirectURI: '[REDIRECT_URI]',
      state: '[STATE]',
      nonce: '[NONCE]',
      usePopup: true | false,
    });

    try {
      const res = await window.AppleID.auth.signIn();
      console.log(res);
    } catch (error) {
      console.log(error);
    }
  };

  return <button onClick={loginWithApple}>Apple 로그인</button>;
};

export default AppleLogin;
  • clientId: 애플리케이션을 식별하는 데 사용돼요. Apple Developer 계정에서 Service IDs를 생성하면서 설정한 Identifier를 작성해주면 됩니다.
  • scope: 사용자의 정보 중 애플리케이션이 요청하려는 부분을 명시합니다. 예를 들어, email은 사용자의 이메일 주소를 요청하겠다는 뜻입니다.
  • redirectURI: 사용자가 성공적으로 로그인한 후에 리디렉션될 URL을 가리킵니다. Services IDs를 설정할 때 등록해야 합니다.
  • state: 이는 애플리케이션에서 생성한 고유한 문자열로, 보안을 강화하는 데 사용됩니다. 이 문자열은 사용자가 로그인을 시작한 후에 'redirectURI'에 전달됩니다. 애플리케이션은 이 문자열을 검증하여 요청이 변경되지 않았음을 확인할 수 있습니다.
  • nonce: nonce는 'number used once'의 줄임말로, 한 번만 사용되는 임의의 수를 의미합니다. 이는 보안을 위해 사용되며, 주로 재전송 공격(replay attacks)을 방지하는 데 사용됩니다. 사용자가 'Sign in with Apple' 버튼을 클릭하면, 애플리케이션은 nonce 값을 생성하고 이를 Apple에 전달합니다. Apple은 이 nonce 값을 사용자의 세션에 연결하고, 사용자가 인증을 완료하면 이 nonce 값을 리디렉션 URL의 일부로 반환합니다. 애플리케이션은 이 nonce 값을 검증하여 요청이 변경되지 않았음을 확인할 수 있습니다.
  • usePopup: 이 설정은 'Sign in with Apple' 프로세스가 팝업 창에서 실행될지 또는 현재 창에서 실행될지를 결정합니다. 이 값이 true로 설정되면, 사용자는 현재 페이지를 떠나지 않고 'Sign in with Apple' 프로세스를 완료할 수 있습니다. 반대로 이 값이 false로 설정되면, 사용자는 새 창에서 'Sign in with Apple' 프로세스를 완료해야 합니다. 사용자 경험을 고려하면, 대부분의 경우 usePopup을 true로 설정하는 것이 좋습니다.

여기선 usePopup을 true로 설정해 놓고 시도해 볼게요. 위에서 만든 AppleLogin 컴포넌트를 렌더링한 후 클릭해 봅시다.

Untitled 4

클릭하면 위 캡쳐와 같이 Apple ID 로그인 창이 뜨는데요. usePopup 값을 true로 설정해주면 새 창으로 뜰 것이고, 지정하지 않거나 false로 지정하면 페이지가 appleic.apple.com 으로 redirect 됩니다. 전에 Apple Developer로 지정한 계정과 상관 없이 로그인하고 싶은 Apple 계정으로 로그인합니다.


Untitled 5

그럼 위와 같이 계속 사용하겠냐는 문구가 드는데, 계속을 누르면 팝업 창이 닫히고 API 호출 응답을 내려줍니다. 아까 코드에서 console.log로 출력해 놓았으니 console 창을 확인해볼게요.


Untitled 6

정상적으로 잘 내려온 것을 확인할 수 있습니다. 저는 AppleID.auth.init() 메서드를 호출할 때 state 값으로 origin:web 값을 넘겨 주었는데요. 이 문자열을 검증하여 요청이 변경되지 않았음을 확인할 수 있습니다.

  • code: 애플 서버에서 발급한 임시 인증 코드입니다. 이 코드는 클라이언트에서 서버로 전달되며, 서버는 이 코드를 사용하여 Apple 인증 서버에서 액세스 토큰을 받아옵니다. 이 액세스 토큰은 Apple ID 사용자 정보를 검색하는 데 사용됩니다.
  • id_token: 사용자가 누구인지 식별하는 데 사용됩니다. 이 토큰에는 사용자의 Apple ID 이메일 정보와 nonce 값이 포함되어 있습니다. 이 토큰은 서버에서 검증하여 신뢰성을 확보합니다.

타입 설정

위 내용까지만 해도 애플 로그인을 구현할 수 있습니다. code와 id_token 값을 활용해 서버와 통신하면서 서비스의 계정 시스템과 연동할 수 있어요. 다만 타입 안정성을 위해 Typescript 타입을 추가해 주겠습니다.

※ 타입은 https://developer.apple.com/documentation/sign_in_with_apple/clientconfigi 페이지를 참고해서 작성했습니다. 실제 제공되는 타입과 다를 순 있지만, 사용하는 데에는 충분할 것으로 판단됩니다.

interface ClientConfig {
  clientId: string;
  redirectURI: string;
  scope?: string;
  state?: string;
  nonce?: string;
  usePopup?: boolean;
}

interface Authorization {
  code: string;
  id_token: string;
  state?: string;
}

interface User {
  email: string;
  name: string;
}

interface SigninResponse {
  authorization: Authorization;
  user?: User;
}

interface SigninError {
  error: string;
}

// script 추가 시 window 객체에 AppleID가 추가되므로 declare 키워드를 통해 추가해줍니다.
declare global {
  interface Window {
    AppleID: {
      auth: {
        init: (config: ClientConfig) => void;
        signIn: (config?: ClientConfig) => Promise<SigninResponse>;
      };
    };
  }
}

이렇게 작성해두면 window.AppleID 객체를 사용할 때 적절히 타입이 부여돼서 자동완성 기능으로 간편하게 사용할 수 있고, 나머지 항목들은 적절히 내보내기(export) 해줘서 사용하시면 됩니다.


디자인 가이드라인

다른 소셜 로그인 기능들과 마찬가지로 애플 로그인 기능도 디자인이 가이드가 있습니다. 애플 로그인 디자인 가이드는 여기서 확인 가능합니다.

저희 서비스에서는 카카오와 구글 로그인을 제공하고 있는데요. 이제 애플 로그인이 도입이 된다면 3가지 소셜 로그인을 제공하게 됩니다. 관련해 디자인 가이드를 적절히 지키지 않는다면 배포나 서비스 이용에 당장 문제가 있는 것은 아니지만, 사용 제재가 들어올 가능성은 있기에 가이드 라인을 지켜서 사용하는 것을 권장하고 있습니다.

image

정리

이 글에서는 웹 서비스에 애플 로그인을 도입하는 방법에 대해 살펴보았습니다. 애플 로그인은 사용자의 애플 아이디를 활용하여 로그인하는 기능으로, 애플의 엄격한 보안 및 개인정보 보호 기준을 준수합니다. iOS 앱 스토어 심사에 따라 추가하긴 했지만, 이 기능을 웹 서비스에 도입하면 사용자의 신뢰도를 높일 수 있습니다.

요약하자면 애플 로그인을 도입하는 과정은 크게 세 단계로 이루어집니다.

  1. Apple Developer 계정에서 식별자와 키를 설정하여 Apple Service ID를 발급받습니다.
  2. 이 ID를 활용하여 React 웹에 애플 로그인을 구현합니다.
  3. 구현된 로그인을 바탕으로 서버와 통신하여 계정 시스템과 연동합니다.

사실 다 해놓고 보면 별거 없는 느낌이긴 합니다. 공식 문서에 정리도 잘 되어있고, 따라가면 예상한대로 동작하기도 해요. 그런데 관련 정보가 영어로 되어있어서 조금이라도 정리해놓고 필요한 정보만 모아놓으면 좋겠다 싶어서 정리했는데, 나중에 다른 서비스에서 도입한다 하더라도 참고할 수 있을 것 같습니다.


참조

profile
프론트엔드 개발자 배준형입니다.

0개의 댓글