OAuth 흐름 이해하기

2023년 07월 15일

OAuth를 개발자 입장에서 이해해보자.

내가 사용자로 쓸 때는 편했지만,, 처음 개발할 때 많은 개념들이 많아서 잘 이해가 가질 않았다. API 문서를 보면 정말 많은 것들이 나온다. client_id, client_secret, redirect_url, authorization_code, access_token, refresh_token, OAuth Scope. 보통의 다른 API라면 1-2개 token, id 정도로 다 되었던 것 같은데.

OAuth를 도와주는 다른 라이브러리를 가져다 쓸 수도 있지만 개념을 이해하는 건 꼭 필요하다. 그래야 이게 어떻게 작동하는지, 개발자가 받은 token을 어디에 저장하고 보관할지, 어떤 보안상 이슈가 있을지 알 수 있다. 보통의 OAuth 플로우는 비슷하니 한번 익혀두면 어떤 서비스든지 연결할 수 있다.

OAuth의 기능

OAuth는 아래와 같은 목적을 위해 만들어졌다.

‘로그인한 서비스’ 계정의 데이터를 사용할 수 있게 해준다. 페이스북의 OAuth를 활용한다면 페이스북에 있는 사용자의 정보를 읽거나, 게시물을 대신 올릴 수 있게 된다. 구글 OAuth를 쓴다면 구글에 있는 사용자 정보를 가져오거나, Gmail의 데이터를 읽거나 Gmail로 메일을 발송할 수 있게 해준다. 개발자가 원하는 권한을 OAuth 과정에서 요청할 수 있고 유저의 승인 후 권한이 부여된다.

OAuth로 “____으로 로그인”같이 다른 서비스로 로그인하는 기능을 구현할 수도 있다. “____으로 로그인” 같은 로그인 기능만 활용하려면 OAuth 보다는 OAuth 안에 있는 개념인 OpenID를 활용한다. (요건 추후 포스팅으로)

OAuth의 흐름

한 번에 모든 구조를 이해하려고 하지 말고, 한 단계씩 살펴보면 이해가 쉽게 된다.

client_id, client_secret, redirect_uri, authorization_code, access_token, refresh_token 등등 → 한번에 다 이해하려고 하지 말고, 한단계 씩 쪼개보자

0. 사전 준비

  • 여기서는 [구글] 로그인을 예시로 사용한다.
  • [구글] 로그인을 사용할 내 웹or앱 어플리케이션을 준비한다. 이하 [마이앱] 이라고 부른다
  • 구글 cloud console에서 [마이앱] 을 등록하고 client_id, client_secret를 발급받는다.
    • 이때 [마이앱] 의 redirect_uri을 입력한다.
      • redirect_uri : 유저가 구글이 제공한 화면에서 접근 권한을 승인한 후에 다시 돌아올 [마이앱] 의 url이다.
      • 로컬 환경에서 테스트 하기위해 실제 앱의 url, 로컬버전의 url을 각각 입력하기도 한다.

1. “구글로 로그인하기” 버튼 클릭

사용자가 “구글 연동하기” (혹은 “구글로 로그인하기”) 버튼을 클릭하면, 구글의 OAuth API로 client_id, scope, redirect_uri 정보를 담아 요청을 보낸다.

  • client_id : client_id를 근거로 구글이 [마이앱]에서 이 사용자의 데이터를 원하는 구나’하고 알 수 있다.
  • scope : 사용자의 어떤 데이터, 권한을 요청하는지.
    • 예를 들어) 이메일 주소, 이름, 프로필 사진에 대한 ‘읽기’ 권한을 요청할 수 있다.
  • redirect_uri도 보통 이때 같이 보낸다.

2. [마이앱]의 redirect url에서 authorization_code를 받는다!

  • [구글]이 사용자에게 동의 화면을 띄우고 사용자가 승인을 누르면 내가 1번 요청에서 함께 보낸 [마이앱]의 redirect_uri로 돌아간다.
  • 구글이 사용자를 [마이앱]의 redirect url로 보낼 때 authorizaion_code를 담아서 보내준다.

https://www.myapp.com/api/auth/google/redirect?authorization_code=df23sdf5twh...

  • [마이앱]은 이 authorizaion_code을 꺼내서 사용하면된다.

자! authorization_code을 얻었다. 하지만 아직 사용자의 정보를 얻을 수 없다. authorization_code는는 access_token을 얻는데 사용한다. 이 access_token을 받고서야 실제 사용자의 데이터를 요청할 수 있게 된다.

3. 진짜 필요한 키 access_token을 받자.

  • [마이앱]에서 client_id, client_secret, authorization_code 3개로 [구글] OAuth API에 요청을 보낸다.

이 요청이 성공하면 드디어 [구글]에서 access_token을 받을 수 있다. 이제 이 access_token으로 드디어 사용자의 데이터를 얻을 수 있다.

4. access_token으로 사용자의 정보를 가져오자

access_token으로 사용자의 정보를 조회하거나, 데이터를 조작할 수 있다. (허가 받은 권한 범위 안에서). 이 요청은 다른 평범한 API들처럼 요청하면 된다.

하지만 이 access_token은 유효기간이 있다. 무한정 사용할 수 없다.

5. refresh_token 으로 access_token 갱신하기

처음 [구글]에서 access_token을 받을 때 이 token의 expire 정보, refresh_token을 같이 받게 된다. 유저의 다시 데이터를 읽고 쓰기위해서 4번 과정에서 처럼 access_token을 사용하게 될 텐데, 이 access_token이 만료되는 때가 온다. 그럼 refresh_token을 사용해서 새로운 access_tokenrefresh_token을 받으면 된다.

6. [마이앱] 개발자 입장에서 token 관리

기본적인 플로우는 이렇다. 그럼 [마이앱]의 개발자는 access_token, refresh_token을 어떻게 관리해야할까?

3번 단계에서 access_token, refresh_token을 DB에 안전하게 저장하자. access_token이 만료되어 새로운 access_token, refresh_token을 받는다면 다시 안전하게 DB에 저장하자. 그렇지 않으면 authorization_code 단계부터 매번 다시해야한다.

주의사항

access_token, refresh_token은 절대 클라이언트 사이드에 노출이 되지 않게 한다. access_token, refresh_token 은 사용자의 데이터에 접근할 수 있는 최종 키이기 때문에 안전하게 관리되어야한다. ‘안전한 방법으로’ 서버 내부에 저장한 뒤 필요할 때 꺼내 사용해야 한다.

다른 궁금증

Q. ‘____으로 회원 가입 / 로그인할 때 [마이앱]은 어떻게 회원 Authentication 처리를 해야할까?

  • OAuth 플로우를 통해 받은 access_token으로 email 같은 사용자 정보를 받을 수 있다. 이걸 회원 식별 정보로 사용하고 싶다면 따로 DB에 저장한다.
  • 로그인 시에는 OAuth 플로우를 통해 사용자 정보를 확인하고, 이 정보가 DB의 사용자 정보와 일치된다고 확인되면 세션 설정을 한다. (기본적인 세션 관리는 비밀번호 로그인, 이메일로 로그인과 다르지 않다.)
  • OAuth 말고 OpenID를 활용할 수도 있다. 구글, 카카오는 OpenID를 기능을 제공한다. OpenID에서는 사용자 Authentication에 사용할 사용자의 프로필 정보, 이메일을 가져오는데 쓰인다. OAuth와는 다르게 사용자의 데이터를 수정할 수 있는 권한을 부여하지는 않는다.

Q. OAuth는 왜 이렇게 여러 단계를 거처야 할까? 왜 한번에 access_token을 받지 않고, authorization_code을 받고 나서야 왜 다시 access_token을 요청해야할까?

authorization_code 단계를 거치는 것이 보안에 이점이 있어서다. redirect_uri를 통해서 바로 access_token을 부여하면 access_token이 브라우저에 노출된다. access_token이 노출되면 이것만으로도 사용자 대신 데이터를 읽고 쓰고 수정할 수 있게 된다.

참고 자료


TAGS
AUTH