OAuth 2.0: 카카오 로그인 구현에서의 고민과 해결

·2024년 10월 27일
post-thumbnail

OAuth 2.0 기반 카카오 로그인 구현을 진행하며, 소셜 로그인에서 발생할 수 있는 보안 및 사용자 경험 문제를 고민한 과정을 정리합니다.

OAuth 2.0

OAuth 2.0 (Open Authorization 2.0, OAuth2)은 권한 부여를 위한 개방형 표준 프로토콜입니다. 사용자가 앱에 로그인 사용자 인증 정보를 증명하지 않아도 앱이 사용자의 보호된 리소스를 제한적으로 액세스하도록 허용합니다.

여기서 사용자는 우리의 서비스, 앱은 리소스 서버(인증 권한 부여 서비스; ex) 카카오, 구글 등) 입니다.

발생 배경

실제 개발하는 서비스에서 리소스 서버에 직접 사용자 정보(IP/PW)를 주고받을 때 발생하는 다양한 문제를 해결하고자 나왔습니다.

OAuth 구조 및 역할

OAuth 2.0에서는 네 가지 주요 역할이 있습니다:

이름실제 대상설명
리소스 소유자카카오 계정을 가지는 개인 사용자사용자가 소유한 자원(예: 사진, 개인 정보)에 대한 접근 권한을 부여하는 주체
리소스 서버카카오 플랫폼 서버클라이언트가 유효한 토큰을 제시할 때 보호된 자원(예: 사용자 정보)을 제공하는 서버
클라이언트내가 개발하는 서비스리소스 소유자를 대신하여 리소스 서버에 접근을 요청하는 애플리케이션
권한 부여 서버카카오 로그인 API클라이언트에게 인가 코드 및 액세스 토큰을 발급하여 자원 접근을 중재하는 서버

OAuth 흐름

권한 부여 승인을 위해 생성한 권한 부여 코드를 전달하는 방식으로 많이 쓰이고 기본이 되는 방식입니다. (Authorization Code Grant)

  1. 권한 요청: 클라이언트는 권한 부여 서버를 통해 리소스 소유자에게 자원 접근 권한을 요청합니다.
  2. 권한 부여 코드 발급: 리소스 소유자가 요청을 승인하면, 권한 부여 서버는 클라이언트에 권한 부여 코드를 전달합니다.
  3. 액세스 토큰 요청: 클라이언트는 권한 부여 서버에 권한 부여 코드를 제시하고, 액세스 토큰을 요청합니다.
  4. 액세스 토큰 발급: 권한 부여 서버는 요청을 검증하고 클라이언트에 액세스 토큰을 발급합니다.
  5. 자원 요청: 클라이언트는 액세스 토큰을 사용해 리소스 서버에 보호된 자원을 요청합니다.
  6. 자원 제공: 리소스 서버는 접근 토큰을 검증한 후 유효한 경우 요청된 자원을 클라이언트에 제공합니다.

아래는 RFC 6749에서 제공하는 Authorization Code Grant 플로우를 입니다.

기본적인 흐름을 파악했다면, 실제 카카오 로그인을 통해 실제 플로우를 파악합니다.

카카오 로그인

소셜 로그인을 지원하는 다양한 플랫폼은 공시 문서로 자세하고 친절하게 설명되어있습니다.

카카오 로그인 흐름

카카오 로그인을 통해 사용자가 서비스에 접근하는 과정은 OAuth 2.0의 Authorization Code Grant 방식을 기반으로 하며, 카카오 API 플랫폼이 이를 지원합니다.

전체 흐름은 다음과 같습니다.

  1. 카카오 로그인 버튼 클릭: 사용자가 애플리케이션 내에서 카카오 로그인 버튼을 클릭하여 클라이언트가 카카오 API 서버에 인가 코드 요청을 시작합니다.
  2. 사용자 인증 및 동의 요청: 카카오 API 서버는 사용자에게 인증을 요청하고 동의를 받습니다. 사용자가 동의하면 인가 코드가 발급됩니다.
  3. 인가 코드 발급: 권한 부여 승인이 완료되면, 카카오 API 플랫폼은 인가 코드를 발급하고 이를 포함한 리다이렉트 URI로 사용자를 서비스로 되돌려 보냅니다.
  4. 토큰 발급 요청: 서비스는 리다이렉트 URI에 포함된 인가 코드를 사용해 카카오 API 플랫폼에 액세스 토큰을 요청합니다. 카카오 플랫폼은 이 요청을 검토한 후 사용자와 애플리케이션을 연결하고, 액세스 토큰을 발급합니다.
  5. 회원 확인 및 등록: 서비스는 발급받은 액세스 토큰으로 카카오 API의 사용자 정보 가져오기 엔드포인트에 요청을 보내 사용자 정보를 확인합니다. 이 정보를 통해 회원 가입 여부를 결정하고, 신규 사용자라면 회원 등록 절차를 수행합니다.
  6. 로그인 세션 발급: 서비스는 사용자 정보를 확인 후, 클라이언트에 로그인 세션을 발급하여 사용자가 정상적으로 로그인되었음을 확인합니다. 이후 로그인된 화면으로 리다이렉트하여 사용자에게 서비스를 제공합니다.

아래는 카카오에서 제공하는 카카오 로그인서비스 과정입니다.

연결 진행

HTTP 요청을 보낼 수 있는 환경이라면 어디서든 이용 가능한 REST API를 사용해서 진행합니다.

카카오 로그인 구현하기 앞서, kakao developers에서 연결하고자하는 애플리케이션을 등록합니다.

카카오 로그인 설정 과정은 카카오 로그인의 ‘설정하기’에서 자세하게 볼 수 있습니다.

아래는 카카오 로그인을 구현하기위 한 최소한의 설정을 진행합니다.

  1. 애플리케이션 추가

  1. 카카오 로그인 활성화 설정
    [내 애플리케이션] > [카카오 로그인] > [활성화 설정]의 [상태]

  2. Redirect URI 설정 : 카카오 로그인은 서비스 로그인 과정에서 Redirect URI를 통해 서비스에서 요청한 인가 코드와 토큰을 전달합니다.
    [내 애플리케이션] > [카카오 로그인] > [Redirect URI] > [Redirect URI 등록]

    • 사용자가 권한을 동의하면 이동한 경로(path)을 입력해야합니다. 이는, 프로젝트 및 팀 상황에 따라 애플리케이션의 클라이언트일수도 서버일수도 있습니다

  3. 동의항목 설정: 카카오 API 플랫폼의 사용자 동의 필요 정보 또는 접근권한 필요 기능에 대응하는 항목으로, 동의항목을 사용해 사용자에게 접근 권한 인가를 요청할 수 있습니다.

    [내 애플리케이션] > [카카오 로그인] > [동의항목]

    • 애플리케이션에서 카카오 로그인시에 사용자에게 보여줄 동의항목과 사용자에게 수집할 사항들을 선택할 수 있습니다.
동의항목 설정동의 항목

  1. REST API키 설정 : 카카오 로그인시에 필요한 API키를 프로젝트 환경변수에 설정해줍니다.

REST API 방식의 로그인 과정

위에서 언급한 카카오 로그인 과정을 REST API로 상세하게 그려진 시퀀스 다이어 그램입니다.
node.js로의 자세한 구현은 아래의 링크를 참고하시면 좋습니다.

카카오 로그인 과정에서 가지는 의문점

카카오 로그인 구현 과정에서 프론트엔드와 백엔드간의 의견이 조율이 필요 했습니다.

위의 과정에서 ‘Step1: 인가 코드 받기’에서의 302 Redirect URI로 인가 코드 전달에서 “Redirect URI의 위치는 어디로 해야하는 가?” 였습니다.

소셜 로그인을 제공하는 다양한 플랫폼에서 Redirect URI는 서버로 리다이렉트 시킨후에 토큰을 발급받는 과정을 설명합니다.

또한, 그것을 권장하기도 합니다.

하지만, 구글링해보면 다양한 서비스와 사람들이 프론트엔드에서 인가코드를 수신하고 다시 백엔드로 요청보내는 로직을 구현하고 있습니다.

이유가 뭘까요?

논의 : Redirect URI 설정은 어디로 해야할까? (인가코드 수신의 위치)

팀프로젝트에서 인가코드처리에 대해서 백엔드 팀원과 논의를 시작하면서 더 고민하게 되었습니다.

고민 : Redirect URI 설정은 어디로 해야할까? (인가코드 수신의 위치) 정한다면 그 근거는?

으레 이런 부분에서는 공식문서를 따르지만 이번에는 좀 더 근거를 찾고싶었습니다.

많은 사람들이 인가 코드 수신을 프론트엔드에서 진행하는 걸까요?

인가코드는 이름부터 보안적 문제가 될 것 같아 보이기도 하며, 외부 API를 왜 프론트엔드를 한 번 더 경유해서 개발하고 있는걸까요?

처음에는 Oauth2의 흐름조차 이해하기 힘들어서 로컬에서 프론트엔드 단에서 카카오 로그인의 전체 플로우를 작성해서 시도해보았습니다.

그렇게 깨달은 점은 인가코드 수신을 프론트엔드에서 하는 이유는 사용자 경험을 위한 것이었습니다.

위에서 다이어그램에서 확인했듯이 사용자가 [카카오 로그인] 버튼을 클릭 할 경우 아래의 플로우가 진행됩니다.

  1. 카카오 로그인 창 오픈 후, 사용자가 카카오 로그인 진행

  2. 로그인이 완료되었다면, 애플리케이션에 정보를 제공할 동의 화면 표시

  3. 동의할 경우 설정할 Redirect URI로 라우팅하여 인가코드 수신

  4. 인가코드를 활용하여 카카오에서 token 발급 받기

인가코드를 백엔드에서 수신할 경우, 사용자 동의 진행후에 3, 4, 5가 진행이 완료 될 때 까지 멈춰있는 화면을 보게 됩니다. 즉, 아무런 피드백을 받을 수 없게 됩니다.

최초 로그인 및 회원가입에서는 크게 문제가 되지 않을 수도 있겠지만, 이미 해당 애플리케이션에 로그인 전적이있는 사용자가 카카오 로그인을 자동으로 등록 해놓는다면 [카카오 로그인] 버튼을 클릭후에는 아무런 인터렉션을 받아보지 못한채 애플리케이션의 로그인이 완료되면 적절한 리다이렉션이 일어납니다.

이를, 보완하고자 인가 코드를 프론트엔드에서 수신하여 인가코드를 사용해서 token을 발급받고 애플리케이션의 로그인 및 회원가입을 진행하는 과정에서는 로딩 화면으로 사용자에게 진행사항을 알릴 수 있습니다.

즉, 사용자에게 4, 5가 진행되는 동안에 로그인 및 회원가입이 진행되고 있다는 것을 제공해줄 수 있습니다.

Redirect URL이 백엔드일경우Redirect URL이 프론트엔드일경우

추가 고민 : 그렇다면 인가 코드의 보안은?

인가 코드 수신을 서버에서 진행하는 것을 권장하는 이유에는 인가 코드의 중요성이지 않을까 싶었습니다.

Redirect URI를 프론트엔드로 설정하고 인가코드를 수신하게되면 실제 URL 상에서 인가코드를 탈취 할 수 있기 때문입니다.

그렇다면 인가코드가 어떻게 보안처리가 되어있는 가에 대해서 더 찾아보게 되었습니다.

RFC 6749에 따르면, 인가 코드의 보안은 주로 아래의 방식으로 보호되어 인가 코드가 탈취되거나 악용되는 것을 방지한다고 합니다:

  1. 인가 코드의 유효 기간: 인가 코드는 발급 후 짧은 시간 내에 만료되도록 설계되어 있어 코드가 노출되더라도 사용 기간이 제한됩니다. RFC 6749에서는 인가 코드의 최대 유효 기간을 10분으로 설정하는 것을 권장합니다.
  2. 인가 코드의 단일 사용성: 인가 코드는 단 한 번만 사용될 수 있습니다. 즉, 같은 인가 코드로 여러 번의 토큰 요청을 할 경우 서버는 이를 차단하고, 코드가 더 이상 유효하지 않도록 처리합니다. 이를 통해 인가 코드가 탈취되더라도 반복적인 사용을 방지할 수 있습니다.
  3. 리디렉션 URI 검증: 인가 코드가 클라이언트에게 전달되는 과정에서, 클라이언트가 최초 요청한 리디렉션 URI와 일치하는지 확인하는 절차가 있습니다. 인가 코드가 발급된 URI와 다른 URI에서 토큰 요청이 들어오면 서버는 이를 차단합니다. 이를 통해 코드 탈취 및 잘못된 URI로의 재전송 위험을 줄일 수 있습니다
  4. TLS 사용: 클라이언트와 서버 간 통신에 TLS를 사용하여 네트워크 상에서 인가 코드가 탈취되는 것을 방지합니다. 특히 인가 요청과 토큰 요청에 대한 데이터가 안전하게 전송될 수 있도록, 권한 부여 서버와 토큰 서버는 TLS를 필수로 사용해야 합니다

이렇게 찾은 내용들을 정리하여 간단하게 제안을 건내어 애플리케이션의 클라이언트 경로를 Redirect URI로 설정하고 프론트엔드에서 인가코드를 수신하여 백엔드로 전달하는 방식을 채택하였습니다.

마무리

구현 내용을 더 작성하지 않고 왜 마무리 하느냐 하면, 어떠한 고민을 했고 어떠한 선택을 하게 됐는지 작성하고 싶었기 때문입니다.

인증인가에 대한 전략은 팀과 프로젝트 상황에 따라 다를 수 밖에 없습니다. 요청하고 요청받는 것에 대한 내용은 다른 공식 문서 뿐만아니라 다양한 글에서 확인 할 수 있었습니다.

제가 OAuth2기반 소셜로그인 구현을 진행하면서 고민한 내용을 작성하고 싶었고, 나뿐만 아니라 다른 분들도 한번 쯤은 고민하지 않았을까 하는 생각에 포스팅을 하게 되었습니다.

Next.js 14 App dir 기준으로 구현 한 내용은 아래의 링크를 확인할 수 있습니다.

https://github.com/j2h30728/boost-pal/pull/50

profile
성실하게

0개의 댓글