🌱 해당 포스트는 한걸음 스터디에서 발표한 내용입니다. 발표 내용을 아래 영상에서 확인하실 수 있습니다.

🌱한걸음은 각자 학습한 내용을 토대로 블로그 글을 작성하고, 대면으로 모여서 발표하며, 녹화해 유튜브에 업로드하는 스터디입니다.

한걸음 자세히 알아보기

들어가며

요즘 웹/앱 서비스를 만들 때 위처럼 소셜 로그인 기능을 구현하는 경우가 많습니다. 특정 웹사이트에 직접 가입하지 않고, 사용자의 타 서비스 계정을 이용해서 가입을 하는 방법입니다. 이번 시간에는 이러한 소셜 로그인을 구현할 수 있게하는 원리에 대해서 알아보겠습니다.

OAuth 2.0 이란?

OAuth 2.0을 간단하게 말하면 "사용자가 사용 중인 다른 서비스를 우리 앱에서 대신 이용하는 방법" 이라고 할 수 있습니다. OAuth 2.0의 자세한 스펙을 RFC 6749 문서에서 자세히 살펴볼 수 있습니다.

우선 여기 우리가 만든 앱과 사용자가 있다고 해보겠습니다. 구체적인 예시가 있으면 좋으니, 간단히 사용자의 스포티파이 재생목록으로부터 MBTI를 맞춰주는 서비스를 한 번 만들어 봅시다. (스포티파이는 멜론처럼 해외에서 사용되는 음악 스트리밍 서비스입니다)

이미 플레이리스트를 입력하면 MBTI를 추출해주는 시스템이 만들어져 있다고 가정하겠습니다. 필요한 건 사용자의 플레이리스트입니다. 이를 입력받는 방법은 다양할 것입니다. 가장 단순한 방법은 사용자가 모조리 입력하는 것입니다. 하지만 아무래도 다 적기 전에 사용자가 떠나버릴 확률이 더 크겠죠. 두 번째 방법은 저희 쪽에서 스포티파이로부터 직접 가져오는 방법입니다.

스포티파이로부터 재생목록을 어떻게 가져올 수 있을까요? 사용자의 플레이리스트는 비공개로 설정되어 있어서 오직 로그인한 사용자만 볼 수 있다고 가정하겠습니다. 저희 앱은 해당 재생목록에 접근할 권한이 없습니다. 가장 단순한 방법으로는 사용자로부터 스포티파이 아이디와 비밀번호를 직접 받는 방법이 있겠습니다.

단순하지만 딱 봐도 어딘가 잘못되었다는 느낌이 옵니다. 사용자 입장에서도 저희한테 아이디와 비밀번호를 냅다 건내주기 부담스럽고, 서비스의 입장에서도 사용자의 아이디와 비밀번호를 잘 간수해야 하는 것은 큰 부담입니다. 모든 정보에 대한 완전한 권리를 양도한다는 것은 보안상 많은 허점을 만듭니다.

이때 우리는 OAuth 2.0을 이용할 수 있습니다. 스포티파이를 비롯해 여러 서비스에서는 OAuth 2.0 방식으로 사용자로부터 인증을 받고 데이터를 제공받는 방법을 지원하고 있습니다. 대신 조금 더 복잡한 절차가 추가됩니다.

OAuth 2.0에서의 역할

우선 OAuth 2.0이 정의하고 있는 역할에 대해 먼저 이야기하겠습니다. 앞으로는 이 역할을 기준으로 설명할 것이기 때문입니다. OAuth 2.0에서는 총 4개의 역할이 있습니다.

  1. Resource Owner
  2. Client
  3. Resource Server
  4. Authorization Server

갑자기 용어가 늘어나 당혹스러울 수 있지만 앞에서 다 나왔던 친구들이기 때문에 걱정하실 필요 없습니다.

Resource는 앞에서 말한 사용자만 접근이 가능한 다른 서비스에서의 데이터입니다. 저희 앱이 필요로 하는 데이터라고도 말할 수 있겠습니다.

Resource Owner는 해당 Resource의 소유자입니다. 여기서 사용자(End-user)를 말합니다.

Client는 Resource를 요청하고 사용하는 쪽입니다. 사용자의 Resource인 플레이리스트를 요청하는 저희 앱을 말합니다.

Authorization Server와 Resource Server는 각각 "인증을 위한 무언가를 주는 서버"와 "Resource가 저장된 서버입니다." 상황에 따라 이 둘이 같을 수도 있지만 명확한 구성을 위해 OAuth 2.0에서는 이렇게 두 역할을 나누어놨습니다.

OAuth 2.0의 흐름

이제 이 OAuth 2.0이 해당 역할들 사이에서 어떻게 이루어지는지 한 번 알아보겠습니다. OAuth 2.0 프레임워크 문서에는 4가지 방식이 나와있습니다.

  1. Authorization Code : 리소스 소유자가 인가 서버를 통해 인증한 뒤 클라이언트에 인가 코드를 제공하는 방식. 보안성이 높음.
  2. Implicit : 브라우저 기반 클라이언트에서 인가 코드를 생략하고 바로 액세스 토큰을 발급받는 간소화된 방식.
  3. Resource Owner Password Credentials : 리소스 소유자의 아이디와 비밀번호를 직접 사용하여 액세스 토큰을 발급받는 방식으로, 높은 신뢰 관계에서 사용.
  4. Client Credentials : 클라이언트가 리소스 소유자 없이 독립적으로 리소스에 접근할 때 사용.

이 중 주로 사용되는 것은 Authorization Code 방식입니다. 그럼 해당 방식이 어떻게 동작하는지 한번 살펴보겠습니다.

App 등록

말씀드렸다시피 Client는 저희가 개발한 애플리케이션(App)입니다. Authorization Server(이하 Auth Server) 입장에서는 아무나에게 자기네 서비스 로그인 기능을 제공할 수는 없습니다. 그래서 저희 앱이 해당 로그인 서비스와 나아가 제한된 리소스에 접근할 수 있도록 등록하는 과정이 필요합니다.

주로 앱의 이름과 로고 등 기본 정보와 함께, 로그인에 성공하면 브라우저에서 호출될 redirect_uri(혹은 callback_url)을 적어서 제출하면 서비스에서는 해당 앱이라는 것을 인증할 수 있는 client_idclient_secret을 발급하여 줍니다. 이는 내가 해당 서비스에 등록한 앱이라는 것을 증명하는 인증서로 생각해주시면 됩니다. 여기서 client_secret의 경우 저희 앱을 위한 비밀번호나 마찬가지이므로 유저나 다른 곳에 노출되어서는 안 됩니다.

소셜 로그인 화면으로 리디렉션

저희 앱을 사용하는 사용자를 뜻하는 Resource Owner는 "스포티파이로 로그인" 버튼을 클릭해, 로그인을 요청합니다. 그러면 Client는 HTTP 응답(302)을 이용해 Auth Server의 로그인 페이지 URL로 Resource Owner를 이동시킵니다. 302 코드를 받을 때마다 사용자의 브라우저는 자동으로 첨부된 URL로 이동합니다. 이때 해당 URL에는 Auth Server가 우리 앱이라는 것을 확인할 수 있는 client_idredirect_uri, scope 등 몇 가지가 포함됩니다.

여기서 scope는 Client가 소셜 로그인을 통해 정확히 어떤 리소스에 접근할 수 있게할 것인지에 대한 정보입니다. 소셜 로그인으로 이동했을 때 나오는 정보 제공 동의사항에 올라가는 항목들로 볼 수 있습니다. 이는 서비스가 불필요한 리소스에 접근하지 못하도록 하기 위함입니다.

인증 및 리소스 접근 동의

이제 사용자는 Auth Server가 제공하는 로그인 화면에서 로그인 및 Client가 요청하는 리소스 접근에 동의하게 됩니다. 우리가 평소 소셜 로그인 버튼을 눌렀을 때 이동하는 화면입니다.

사용자가 로그인 및 동의를 마치면 Auth Server는 동의까지 받았다는 임시 인증을 위한 code라는 것을 만들어, 우리가 제공했던 redirect_uri로 사용자를 다시 돌려보내면서 code를 해당 URL 파라미터로 붙여줍니다.

엑세스 토큰 획득

앞선 과정은 Auth Server로부터 엑세스 토큰(Access Token)이라는 것을 얻기 위한 과정이었습니다. 엑세스 토큰은 우리가 원하던 사용자만 접근 가능한 리소스에 우리가 접근하는 것을 허락하는 키입니다. 당연하겠지만 엑세스 토큰을 그냥은 얻을 수 없습니다. 내가 사전에 등록된 앱이라는 걸 증명하는 client_secret과 사용자로부터 해당 리소스에 접근해도 된다는 허락을 받았다는 code가 모두 필요합니다.

client_secret 은 원래 우리가 가지고 있고, code는 클라이언트로부터 받아왔으니 이제 엑세스 토큰을 요청하여 Resource Server에 리소스를 요청할 수 있습니다.

리소스 접근 및 사용자 요청 반환

엑세스 토큰을 얻고 나면 이제 Resource Server에 허락된 사용자 리소스에 접근할 수 있습니다. 이로서 저희가 최초에 설계했던 시스템이 완성됩니다.

소셜 로그인

소셜 로그인은 앞선 방식과 마찬가지입니다. 다만 접근하고자 하는 리소스가 플레이리스트 같은게 아닌 사용자의 Email등 사용자를 식별할 수 있는 정보라는 것이 차이점입니다. OAuth 엑세스 토큰을 통해 얻을 수 있는 Email 정보는 이미 사용자로부터 로그인 과정을 거쳐 인증을 받아야만 얻을 수 있는 정보이기 때문에, 그 자체로 비밀번호의 역할을 합니다.
이를 활용하면 개발하는 애플리케이션은 별도의 사용자 인증과정을 거칠 필요 없이 모든 과정을 OAuth Server에 위임할 수 있습니다.

아래는 최대한 간략하게 표현하려고 해본 소셜 로그인 과정입니다. 마지막에는 주로 우리 앱에서 사용자를 식별할 수 있도록 서버 고유의 토큰을 만들어 넘겨주거나 로그인 성공을 알려주며 끝이 납니다.

마치며

이렇게 OAuth 2.0의 큰 그림에 대해서 이해해보는 시간을 가져보았습니다. 단숨에 이해하기 쉽지 않은 시스템이지만, 실제 구현을 위해서 또 다른 자료들을 살펴보시면 감이 오시리라 생각됩니다. 설명드린 내용은 OAuth 2.0 프레임워크의 추상적인 과정이며 실제 구현은 이용하려는 OAuth 서비스마다, 그리고 내가 구현하려는 시스템마다 다양한 방법이 있을 수 있습니다.

예를 들어, 모바일 앱에서 소셜 로그인을 만드실 때에는 모바일 네이티브 환경에 제공되는 SDK를 통해 엑세스 토큰 발급까지 한 번에 처리해주도록 구현되어 있기 때문에, 사용자 모바일 앱에서 Client 서버로 엑세스 토큰을 직접 전달하는 방법이 권장되는 경우도 있습니다. 이는 리디렉션 방식을 이용할 경우 앱에서 사용되는 웹뷰가 웹에서 사용되는 브라우저에 비해 보안상 취약한 부분이 많기 때문이라고 합니다.

따라서 실제 구현을 하실 때에는 이용하려는 OAuth 서비스의 공식 문서를 참고하시는 것이 가장 좋습니다.

추가로 궁금하신 점이나, 피드백을 댓글로 남겨주시면 감사하겠습니다.

참고 자료

profile
안녕하세요, 백엔드 열심히 공부 중인 개발자입니다😊

0개의 댓글

Powered by GraphCDN, the GraphQL CDN