일단 씻고 나가자

[생활 코딩] WEB2 - OAuth 2.0 본문

Backend/OAuth

[생활 코딩] WEB2 - OAuth 2.0

일단 씻고 나가자 2023. 8. 24. 02:22

(본 포스팅은 해당 영상의 정리 및 개인 공부의 목적 포스팅임을 밝힙니다.)
생활코딩. (2018, 08 06).
WEB2-OAuth [비디오 파일].
검색 경로 https://www.youtube.com/playlist?list=PLuHgQVnccGMA4guyznDlykFJh28_R08Q- 

 

WEB2-OAuth

 

www.youtube.com

 

 

 

 

 

1. 수업소개

OAuth란, 나의 애플리케이션 서비스를 이용하는 이용자에게, 다른 애플리케이션의 서비스를 연동해주는 기술이다.

예를 들면, 내가 만든 애플리케이션에 어떤 이용자가 스케줄을 적으면 그것이 구글 캘린더에도 적히는 것,

혹은 흔하게는 구글과 관련된 애플리케이션이 아님에도 구글 아이디로 로그인하기 같은 기능(Federated identity)이다.

 

가장 쉬운 방법으로는 구글의 아이디와 비밀번호 정보를 받아 나의 애플리케이션에 저장하는 방법이 있겠다.

하지만 이 방법은 이용자 입장에서는 보안의 문제(내 구글 정보를 빼가서 악용하면 어떡하지?),

애플리케이션 서비스 제공자 입장에서는 정보 유실의 문제(사용자의 구글 아이디를 저장했다가 해킹당하면 어떡하지?),

회원 정보 제공자 입장에서는 신뢰성의 문제(저 애플리케이션에게 뭘 믿고 내 서비스에 저장된 회원 정보를 주지?)

등의 문제를 야기하게 되어 좋은 방법이라 볼 수 없다.

 

이러한 문제를 해결하기 위해 탄생한 기술이 OAuth이다.

OAuth는 정보를 요구하는 애플리케이션에게, 회원 정보 대신 토큰(accessToken)을 발급하는 것으로 문제를 해결한다.

이때의 accessToken에는 비밀번호 등의 실제 정보가 담기지 않으며, 부분적인 기능만 접근할 수 있도록 허용한다.

따라서 우리의 애플리케이션은 OAuth를 이용해 타 애플리케이션에게 accessToken을 발급 받고, 허용되는 범위 내의 기능에서 이용자에게 안전한 서비스를 제공하게 될 수 있는 것이다.

 

 

 

2. 역할

우선 OAuth의 주요 용어들은 다음과 같다.

  • 이용자 - Resource Owner
  • 회원 정보 제공자 - Resource Server + Authorization Server
  • 서비스 제공자 - Client

위의 예시를 대입해보면 '회원 정보 제공자'는 구글에 해당하며, '서비스 제공자'는 내 애플리케이션 서비스에 해당한다. 

 

OAuth 공식 매뉴얼에선 데이터를 가진 서버를 Resource Server, 인증 관련 자료를 가진 서버를 Authorization Server로 구분하지만, 편의를 위해 앞으로는 Resource Server로 통칭하여 작성한다.

 

 

 

3. 등록

Client가 Resorce Server의 정보를 이용하기 위해서는 사전에 승인을 받는 과정이 필요한데, 이를 등록(register)이라 한다.

개발 과정에서 활용할 땐, 특정 홈페이지(ex. 구글, 페이스북 등)의 개발 파트에 접속하여 정보 입력 후 발급 받을 수 있다.

 

등록 후에 발급 받게 되는 정보는 크게 다음과 같다. (서비스마다 상이할 수 있음)

 

  • Client ID : 우리의 애플리케이션(Client)을 식별하는 아이디 (내 애플리케이션의 ID)
  • Client Secret : 우리의 애플리케이션(Client)을 식별하는 비밀번호 (외부에 노출될 시 큰 보안사고 발생)
  • Authorized redirect URIs : authorized code를 전달 받는 uri (자세한 내용은 후술)

 

 

등록의 과정을 잘 이해하기 위해 예를 들어보자.

 

(등록)

1. 애플리케이션에서 구글 로그인 기능과 구글 캘린더 기능을 활용하기 위해, 구글 개발자 사이트에 접속

 

2. scope는 구글 캘린더, 구글 로그인으로 설정하고, redirect uri를 "https://client/callback"으로 설정

 

3. 확인 버튼을 눌렀더니 구글로부터 Client id = ID, Client Secret = pass를 부여받게 되었다.

 

이제 구글의 데이터베이스에는 다음과 같이 정보가 저장됐다.

Client id ID
Client Secret pass
redirect uri https://client/callback

 

 

 

4. Resource Owner의 승인

새로운 용어인 scope에 대해 우선 알아보자.

scope는 허용 가능하도록 지원하는 기능에 대한 부분으로, 예를 들어 나의 애플리케이션이 구글의 캘린더 기능과 로그인 기능을 제공한다고 했을 때 scope는 캘린더 기능, 로그인 기능이 된다. (이는 등록할 때에 설정할 수 있다)

 

 

이용자 승인 과정의 시나리오를 알아보기 위해, 예를 들어보자.

예시는 이전의 이용자 승인 시나리오와 이어진다.

직관성을 위해 '이용자(Resource Owner)', '구글(Resource Server)', '애플리케이션(Client)'으로 명칭을 바꾸어 설명한다.

 

(이용자 승인)

1. 이용자가 애플리케이션을 이용하다가, 구글 캘린더와 연동이 필요한 서비스를 클릭했다.

[이용자 -> 애플리케이션]

 

2. 구글의 정보가 필요하므로, 애플리케이션은 이용자에게 'Login for google' 이라는 버튼을 띄워서 구글 로그인을 유도한다.

[애플리케이션 -> 이용자]

 

3. 해당 버튼을 누르면 다음과 같은 uri의 사이트로 이동한다.

" https:// resource.server ? client_id = ID & scope = 구글 캘린더, 구글 로그인 & redirect_uri = https://client/callback "

[이용자 -> 구글]

 

4. 구글은 위의 사이트로 접속한 이용자가 만약 구글 로그인이 되어 있지 않다면 로그인 창을 띄운다.

[구글 -> 이용자]

 

5. 이용자가 해당 창으로 로그인을 완료했다. (이용자의 구글 아이디는 USER_ID 이다)

[이용자 -> 구글]

 

6. 구글은 자신의 데이터베이스를 뒤져서, 다음과 같은 순서로 정보를 확인한다.

  6-1. ID 라는 client_id 가 구글의 데이터베이스에 존재하는가?

  6-2. https://client/callback 라는 redirect_uri 가 해당 client_id 가 가진 redirect_uri 값과 일치하는가?

 

7. 모두 일치한다면, 구글은 이용자에게 구글 캘린더, 구글 로그인 기능을 해당 애플리케이션 내에서 사용하는 것에 동의하는지 체크하는 창을 띄운다.

[구글 -> 이용자]

 

8. 이용자는 구글 캘린더만을 허용한다고 체크한 후, allow 버튼을 눌렀다.

[이용자 -> 구글]

 

이제 구글의 데이터베이스에서는 기존 정보가 다음과 같이 업데이트 된다. 

Client id ID
Client Secret pass
redirect uri https://client/callback
user id USER_ID
scope 구글 캘린더

 

 

 

5. Resource Server의 승인

서버 승인 과정의 시나리오를 알아보기 위해, 예를 들어보자.

예시는 이전의 이용자 승인 시나리오와 이어진다.

 

(서버 승인)

1. 구글은 자신의 데이터베이스에 정보를 갱신한 후, authorization code라는 임시 비밀번호를 3으로 애플리케이션에게 발급한다.

 

이제 구글의 데이터베이스에서는 기존 정보가 다음과 같이 업데이트 된다. 

Client id ID
Client Secret pass
redirect uri https://client/callback
user id USER_ID
scope 구글 캘린더
authorization code 3

 

2. 구글은 발급한 authorization code와 redirect uri 이용하여, HTTP 통신 헤더 부의 Location에 https://client/callback/code=3 를 입력하고 이용자에게 보낸다.

[구글 -> 이용자]

 

3. 이용자의 웹브라우저는 header에 의해 해당 uri로 강제 redirect 되어 애플리케이션의 서버로 이동한다.

[(구글)이용자 -> 애플리케이션]

 

4. 애플리케이션은 요청된 uri를 통해 해당 사용자에게 발급된 authorization code가 3임을 알아낸 후,이 정보를 추가한 다음과 같은 uri로 구글에 요청을 보낸다.

" https:// resource.server / token ? grant_type = authorization_code & code = 3 &

redirect_uri = https://client/callback & client_id = ID & client_secret = pass "

[애플리케이션 -> 구글]

 

5. 구글은 uri로 전송된 정보들을 토대로 데이터베이스에서 값이 모두 일치하는지를 확인한다.

Client id ID
Client Secret pass
redirect uri https://client/callback
user id USER_ID
scope 구글 캘린더
authorization code 3

 

 

 

6. 액세스 토큰 발급

액세스 토큰 발급 과정의 시나리오를 알아보기 위해, 예를 들어보자.

예시는 이전의 이용자 승인 시나리오와 이어진다.

 

(액세스 토큰 발급)

1. 구글은 데이터베이스에서 authorization code를 지우고, accessToken 값을 발행하여 저장하고 애플리케이션으로 보낸다.

[구글 -> 애플리케이션]

 

이제 구글의 데이터베이스에서는 기존 정보가 다음과 같이 업데이트 된다. 

Client id ID
Client Secret pass
redirect uri https://client/callback
user id USER_ID
scope 구글 캘린더
authorization code 3
access token "ID'sAccessToken"

 

2. 애플리케이션 또한 authorization code를 지우고, accessToken 값을 받아 저장한다.

 

3. 애플리케이션이 이후 accessToken을 통해 구글에 요청을 하면, 구글은 데이터베이스를 확인하고 구글 캘린더로의 접근을 허가한다.

[애플리케이션 -> 구글]

Client id ID
Client Secret pass
redirect uri https://client/callback
user id USER_ID
scope 구글 캘린더
access token "ID'sAccessToken"

 

 

 

7. API 호출

API는 Application Programming Interface의 약자로, 이용자와 서버가 데이터를 주고 받는 약속(URI)이다.

 

예를 들어 한국에 사는 철수가 어느 나라에 사는지, 어느 언어를 사용하는지도 모르는 영희와 편지를 주고 받는다면

당연히 철수가 아무리 편지를 보낸들 영희는 아무런 답장을 줄 수 없을 것이다.

하지만 영희가 자신의 블로그에 "나는 한국에 사는 영희야. 나는 한글을 써"라고 적어 놓았고, 철수가 영희에게 편지를 쓰고 싶어서 영희의 블로그를 들어갔다면, 철수는 단박에 한글로 편지를 보낼 것이고 영희도 그에 대한 답변을 보낼 것이다.

 

이때 철수는 클라이언트, 영희는 서버이며, 영어는 API에 해당하고 영희의 블로그는 특정 회사의 API 명세를 적어둔 사이트가 될 것이다. 이렇게 클라이언트의 요청에 대해 알맞은 데이터를 보내주도록 서버에서 설계한 URI를 API라 한다.

 

보통 권한이 필요한 기능은 발급 받은 accessToken을 첨부한 URI로 접근해야만 서버에서 올바른 데이터를 전달한다.

(ex. www.영희네 집.com/한글/access_Token=안녕 난 철수야)

 

이때 accessToken을 첨부하는 방법은 크게 두 가지가 있다.

 

  • URI에 토큰을 첨부하여 작성
  • HTTP의 헤더 부에 Authorization : Bearer 로 명시 후 토큰 첨부

 

 

 

8. refresh 토큰

refresh token이란 access token을 갱신해주는 토큰이다.

access token에는 사용자의 정보가 담겨 있어, 토큰의 만료 시간이 길어질수록 보안의 문제가 생기게 되는데

따라서 access token의 만료 시간을 짧게 설정하고, 만료 시에 refresh token을 통해 access token을 재발급해주는 방법이 더 안전하다. (자세한 내용은 후술한다) 

 

OAuth의 공식 문서를 보면 클라이언트와 서버의 토큰을 활용한 통신 절차는 다음과 같다.

 

(A) 앞에 서술한 과정을 통해, Client가 권한을 획득한다.

(B) 서버가 클라이언트에게 AccessToken을 발급해준다. (일반적으로 RefreshToken과 함께 발급받는다)

(C) 클라이언트가 토큰을 통해 요청할 때, AccessToken이 만료되지 않았다면

(D) 서버에서 API에 맞는 보호된 데이터를 제공해주고,

(E) AccessToken의 기한이 만료됐다면

(F) 서버에선 유효하지 않는 토큰 에러를 낸다.

(G) 이때 RefreshToken의 기한이 만료되지 않았다면

(H) 서버에서 새로운 AccessToken을 발급해준다. (Refresh Token도 지속적으로 갱신하는 경우도 있다)

(+) 만일 Refresh Token의 기한 또한 만료되었다면 재로그인을 통해 토큰을 재발급 받는다.

 

Refresh Token은 앞서 살펴보았던 챕터 4~6의 복잡한 과정을 매번 이용자에게 강요하지 않게끔 도와주며,

Access Token 만료 기한의 단축을 가능하게 함으로써 보안성도 높여주게 된다.