OAuth는 인터넷 사용자들이 ID, PW를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.
즉, 현재 서비스의 ID와 PW를 입력하지 않고 인증할 수 있는 프로토콜이다. 예를 들어 Google에 로그인한 후 Google 자격 증명을 이용해서 현재 서비스에 액세스했다면 OAuth를 사용한 것이다.
oAuth는 보통 SSO(Single Sign On) 시스템에서 사용한다. SSO는 1번의 로그인으로 여러 서비스를 이용할 수 있는 시스템을 뜻한다. 즉, SSO 시스템을 구축하기 위해서는 oAuth 프로토콜을 이용한 인증시스템이 필요하다.
oAuth를 이용하는 시스템은 단순히 간단한 로그인 기능 뿐만 아니라 외부 웹 어플리케이션의 API 기능을 활용할 수 있다.
예를 들면, 구글 계정으로 로그인한 A라는 웹 서비스가 있다고 하자. 웹 서비스 A는 Google API에 대한 접근 권한이 있는 상태이므로 Google Calender나 Cloud 같은 API와 연동하는 웹 서비스를 사용자에게 제공할 수 있다.
이처럼 로그인이나 서비스 제공 부분에서 다양한 장점을 제공하기 때문에 oAuth는 많은 웹 서비스에서 사용된다.
oAuth 프로토콜은 크게 4가지 리소스로 구분할 수 있다.
- Resource Server : Client가 제어하고자 하는 자원을 보유하고 있는 서버
- Facebook, Google, Twitter 등 API 제공 서버
- Resource Owner : 자원의 소유자
- A 서비스를 사용하는 클라이언트 유저
- 브라우저 or APP 사용자
- Client : Resoure Server에 접속해서 정보를 가져오고자 하는 웹 어플리케이션
- 웹 서비스 A
- Authorization server : 승인 부여 검증 및 리소스 서버에서 사용자 데이터에 액세스할 수 있는 권한을 앱에 부여하는 액세스 토큰 발급을 담당
다음으로 oAuth 동작 프로세스에 대해서 알아보자.
- 유저가 로그인 페이지에 접속을 한다.
- 로그인 페이지 접속시 유저를 식별하기 위해 생성한 랜덤한
state
값을 사용해 구글 로그인 링크를 생성한다. - 유저는 반환된 구글 로그인 링크를 클릭해 소셜 로그인을 진행한다.
- 소셜 로그인 후에 구글 인증 서버는 토큰 발급을 위한 임시
code
값과 이전에 전송했던state
값을 미리 등록했던 콜백 URL에 붙여 리다이렉트 한다. - 콜백 URL로 호출되는 인증 처리 핸들러에서는
state
값이 이전값과 같은지 확인한 뒤, 받은code
값을 사용해 실제 리소스 사용 권한이 담긴 엑세스 토큰 을 발급 받기 위해 구글 인증 서버로 요청을 보낸다. - 인증 서버로부터 엑세스 토큰을 받으면 필요한 리소스를 요청할 수 있게 된다.
위 글만 봐서는 oAuth 시스템이 동작하는 방식이 헷갈릴 수 있다. 따라서 oAuth의 프로세스를 이해하기 위해 직접 어떤 순서로 구현되는지 알아봤다.
1번째로는 Resource Server(Google)에 client(웹 서비스 A) 등록한다.
등록 절차를 통해 다음 3가지가 생성된다.
- Client ID
- client(웹 서비스 A)를 구별할 수 있는 식별자
- Client Secret
- client에 대한 비밀키
- Authorized redirect URL
- 인증 코드를 전달받을 URL
client ID와 client secret의 차이점은 공개 여부라고 할 수 있다.
client ID는 보통 공개된 상태로 resource server로부터 client를 인증하기위해 사용한다. 하지만 client secret은 비공개 정보로써 인증을 위해 사용하는 것은 똑같지만 client ID처럼 공개적으로 사용해서는 안되는 민감한 정보다.
https://accounts.google.com/login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}?scope={scope}
먼저, 위 링크를 클릭해서 oAuth 로그인을 시도한다. (웹 서비스 A 로그인 페이지에서 구글 링크 누르는 과정이라고 생각하면 됨)
여기서 scope는 Client가 Resource Server로부터 인가받을 권한의 범위다.
참고로 위 링크는 필자가 임의로 작성한 url 링크다.
구글 링크를 눌렀다고 가정하자.
구글 링크를 통해서 로그인을 했다고 하자.
이때, Resource Server인 구글은 쿼리 파라미터로 요청 받은 client_id를 검사하여 동일한 ID가 존재하는 확인하는 작업을 수행한다.
# redirect URL example
redirect_url=https://example.com/login/callback
Google을 통해 인증이 완료되면 redirect URL로 리다이렉트 시킨다. 이때, url 쿼리로 Authorization Code가 함께 전달된다.
몇몇 서비스들은 리다이렉트 이전에 명시된 scope의 권한을 허용할 것인지 한번 더 확인하는 루틴을 가지고 있다.
https://example.com/afterlogin?state={state}&code={Authorization_Code}
리다이렉트 이후에는 위와 같이 state와 code가 파라미터로 설정되고 /afterlogin API로 요청을 보낸다.
access_token={Authorization_TOKEN}&scope={scope}
/afterlogin API에 의해 resource server(구글)로 요청이 전송되고 결과로 위와 같이 token을 부여받는다.
이때, client(웹 서비스 A)는 서버에 token을 저장하고 resource server(구글) API를 할 때마다, token을 http 헤더에 담아서 전송한다.
추가로 Access Token은 만료 기간이 있다. 만약, 만료된 Access Token으로 API를 요청하면 401 에러가 발생한다.
그렇다면, Token을 발급받기위해 다시 로그인해야될까?
보통 Resource Server(구글)는 Access Token을 발급할 때 Refresh Token을 함께 발급한다. Client는 두 Token을 모두 저장해두고, Resource Server의 API를 호출할 때는 Access Token을 사용한다.
Access Token이 만료되어 401 에러가 발생하면, Client는 보관 중이던 Refresh Token을 보내 새로운 Access Token을 발급받는다. 따라서 Token을 발급받기위해 다시 로그인할 필요는 없다.