나는 요즘 선릉 맛집을 소개하고 자유롭게 맛집에 대해 소통하는 커뮤니티가 있는 사이트를 만드는 프로젝트를 진행하고 있다.
모든 사람들이 사용 가능하도록 만드는 중이지만, 우선 주 대상은 위코더 600 여 명을 기준으로 한다.
위코드에서는 주로 구글 계정을 통해 다양한 협업 툴과 사이트 등에 가입을 하게 된다.
그래서 이 맛집 사이트에서도 구글 소셜 로그인 기능을 추가하고자 하는데, 생각보다 다양한 기술이 촘촘하게 엮여 기반되어 있다.
이 기술들을 그냥 눈으로만 보면 잊기가 쉬울 것 같아서, 블로깅을 하며 기록으로 남겨두려고 한다.
오늘은 소셜 로그인 기술의 첫 시작인 OAuth에 대해 알아보자.
(생활코딩 강좌를 통해 알아본 내용을 정리했다.)
OAuth는 여러가지 애플리케이션 기술(PHP, Node.js, Python, Java, Ruby)을 이용하여 구현되는 기술이다.
OAuth와 관련하여 3 개의 참여자가 등장하는데, 각각이 누구인지 먼저 살펴보자.
예를 들어, 사용자가 우리 서비스에 접속해서 글을 쓰거나 봤다면, 나의 서비스가 사용자를 대신해서 구글과 같은 Their의 서비스에 날짜를 기록한다.
이것이 가능하기 위해서는 우리가 사용자로부터 그 사용자가 이용하고 있는 Their의 서비스에 접근할 수 있도록 허가를 받아야 한다.
가장 쉬운 방법은 Their에 있는 사용자의 Id, Password를 Mine에서 저장한 후, 필요시마다 그 정보를 가지고 Their에 접속하는 것이다. 아주 간단하고 Their 서비스의 모든 기능을 사용할 수 있는 방법이지만, 동시에 상당히 위험한 방법이기도 하다. User는 정보 유출을 걱정할 수 있고, Mine은 정보 유실을 막기 위해 막대한 자원을 투자해야 한다.
이런 점을 보완하기 위해 OAuth라는 기술이 탄생했다.
OAuth라는 기술을 이용하면, User의 요청에 의해 Their에서 accessToken이라는 비밀번호를 발급한다. accessToken는 Id, Password와 다른 정보이며 Their 서비스 중 Mine이 필요한 기능만 부분적으로 허용하는 비밀번호이다.
Mine에서 OAuth를 통해 accessToken을 획득한 후, 그 accessToken을 통해 Their의 서비스에 접근하고 데이터를 CRUD할 수 있다.
OAuth에는 3 개의 주체가 등장한다. 그들의 용어와 역할을 살펴보자.
- Client(=Mine)
- Resource Owner(=User)
- Resource Server(=Their) / Authorization Server
- Resource Server: 데이터를 가지고 있는 서버
- Authorization Server: 인증과 관련된 처리를 전담하는 서버
클라이언트가 리소스 서버를 이용하기 위해서는 리소스 서버에 미리 승인을 받아놓는다. 이 과정을 register라고 한다.
필요한 정보
1. Client Id: 나의 사이트를 식별하는 식별자 Id(외부 노출 가능)
2. Client Secret: Client Id에 대한 비밀번호(절대 외부 노출 금지)
3. Authorized redirect URIs: 나의 사이트 URI. (리소스 서버가 권한을 부여하는 과정에서 Client에게 Authorized Code라는 값을 전달해준다. 그 때 이 주소로 전달해달라고 서버에 알려주는 것. 이 주소가 아닌 다른 주소에서 요청이 발생하면, 서버는 이를 무시한다.)
이제 왼쪽 메뉴바에서 API & Services > Credentials 를 클릭하여, API 제어 자격을 얻을 수 있다.
사용자 인증 정보 화면까지 왔다면, '+ 사용자 인증 정보 만들기' 버튼을 클릭하여 OAuth Client ID 만들기를 선택한다. 아래의 동의 화면 구성 문구가 확인될 수 있다.
동의 화면 구성을 클릭하고, User Type을 선택한다. (내부는 G Suite 그룹 내에서만 쓸 수 있는 타입이고, 외부는 일반적인 웹사이트에서 흔히 볼 수 있는 것처럼 모든 사용자가 사용할 수 있는 타입이다.) 나는 누구나 사용할 수 있는 맛집 사이트를 만들고 있기 때문에 외부를 선택했다.
이제 아래와 같은 OAuth 동의 화면이 나타날 것이다.
아직 도메인네임이 없다면, 그 부분은 적지 않고 넘어가도 괜찮다.
다 선택하고 나면 OAuth client의 ID와 secret이 생성된다.
OAuth의 첫번째 절차는 Resource Owner가 Resource Server에게 Client의 접근을 승인한다는 것을 알려주는 것이다.
OAuth에서 앱을 등록하고 나면, Client는 [Client Id, Client Secret]을 가지게 되고, Resource Server는 [Client Id, Client Secret, redirect URL]을 갖게 된다.
주의할 점은, Resource Server가 가진 기능이 A, B, C, D
가 있다고 했을 때 만약 Client가 필요한 기능이 C, D
라면, 그 기능에 대해서만 인증을 만드는 것이 모두에게 더 효율적이다.
이제 Resource Owner의 승인을 위한 단계를 알아보자.
이 때 버튼을 클릭하면 특정 링크로 이동하는데, 그 링크 주소는 resource.server
로 시작하고, query string 형식으로 client id, scope, redirect uri
정보를 담고 있다.
(버튼의 링크를 복사하여 urldecode.org
에서 디코딩을 해보면 알 수 있다.)
특정 링크를 통해 Resource Owner는 Resource Server로 접속한다.
1) Resource Server는 Resource Owner의 로그인 여부를 확인하고, 미로그인 시 로그인을 하라는 화면을 띄운다.
2) Resource Owner가 로그인에 성공하면, Resource Server는 특정링크 상의 client id와 redirect uri 값을 확인하여 자신이 갖고 있는 정보와 대조한다.
3) Resource Server에서 client id와 redirect uri 값이 자신이 가진것과 동일하면, Resource Owner에게 scope에 해당하는 권한을 Client에게 부여할 것인지 확인하는 메세지를 전송한다.
4) Resource Owner가 메세지에서 허용 버튼을 클릭하면, Resource Server는 다음과 같은 정보를 저장한다. '유저 id 1번은 scope b, c에 대한 작업을 허용하는 것이 동의하였다.'
Resource Server는 Client가 등록된 Client가 맞는지 확인하기 위해서 Resource Owner을 통해 Client에게 Authorization code를 전달한다.
이 값을 받은 Client는 이 값과 Client secret의 값을 Resource Server로 전송하여 Client의 신원을 Resource Owner에게 증명한다.
Resource Owner의 허용이 발생한 후에는 Resource Server의 승인이 필요하다.
Location: https://client/callback?code=3
의 형식으로 헤더에 담아 전송하는데, 이는 '해당 주소로 이동하세요'라는 명령과 같다.Resource Owner의 웹브라우저는 로케이션 헤더 값에 의해 해당 주소로 이동한다.
Client는 로케이션 URL의 code=3
값을 통해 authorazation code를 갖게 된다.
Client는 아래와 같은 주소를 통해 Resource Server에 직접 접속한다.
Resource Server는 authorazation code, client ID 값 등 모든 정보를 확인하고, 자기가 갖고 있는 정보와 대조한다.
값이 모두 일치하면 access token을 발급하는 다음 단계를 진행한다.
이 때 가장 중요한 지점은 Client가 Client Secret 값과 authorization code를 함께 Resource Server에 전송하는 부분이다.
Sign-In JavaScript client reference에서 클라이언트 단에서 자바스크립트로 authorization code를 얻는 방법을 확인할 수 있다.
인증이 완료된 이후에 authorization code는 Client와 Resource Server 모두에서 삭제된다.
Resource Server는 accessToken값을 생성하고, 이를 Client에게 전송한다.
Client는 해당 accessToken값을 저장한다.
앞으로 Client가 해당 accessToken값을 통해 Resource Server에 접근하면, Resource Server는 accessToken값을 확인하고 유저 아이디와 유저의 유효기능에 대해 확인한다.
이후 해당 유저 아이디를 가진 사람에게 해당 유효기능만큼 허용하는 동작을 한다.
API가 무엇인지, Access token을 이용해서 API를 호출하는 방법이 무엇인지를 살펴보자.
accessToken을 활용하여 Resource Server를 조작해야 하는데, Resource Server가 Client에게 '우리를 쓰려면 이런 방식으로 동작하십시오.'라는 방식대로 로직을 구성해야 한다.
이 방식이 바로 API이다.
구글 개발자 사이트에서 REST 방식의 API를 확인할 수 있다.
방법 두 가지 중 Authorization: Bearer
방법이 조금 더 안전하고 선호된다고는 하는데, 장단점을 고민해보고 원하는 방법을 사용하면 될 것 같다.
(만약 Authorization: Bearer
방법을 사용한다면 curl examples을 참고해서 command-line으로 내용을 확인해보자.)
Access token은 수명이 있다. Access token의 수명이 다했을 때 새로운 access token을 발급 받는 방법이 refresh token이다.
구글 개발자 사이트에서 보면, 리프레시 토큰을 요청했을 때, 아래와 같이 새로운 access Token을 발급해준다.
그러나 이런 점은 사이트마다 다르게 설정되어 있어서, Refresh token도 계속 갱신될 수 있고 Refresh token은 갱신되지 않고 계속 유지될 수도 있다.
보다 더 자세한 내용을 알고 싶다면, The OAuth 2.0 Authorization Framework의 표준 문서를 확인하자.