개발/개발 공부

OAuth 2.0에 대해 알아보기

codesparkling 2025. 3. 15. 18:12

주제에 대해 학습한 이유
로그인 기능을 Denamu 프로젝트에 도입하면서 OAuth를 사용한 기능을 추가하기로 했다.
(깃헙, 구글, 네이버, 카카오)
그래서 OAuth 기술이 무엇인지, 학습할 필요가 생겼다.
이 학습을 하기 위해, 생활코딩 OAuth 영상을 참고했다.

OAuth

소개

내 서비스가 있고, 사용자가 있으며 나의 서비스가 연동하려는 그들의 서비스가 있을 것이다.
(각각 Denamu, Denamu의 유저, Google이나 facebook이나 twitter 등이 대상에 대입될 수 있다.)

나의 서비스가 사용자를 대신해서 구글의 캘린더에 대신 이벤트를 작성해준다던지, 이런 일을 하고 싶을 수 있다.
우리의 서비스가 그들의 서비스에 접근할 수 있도록 할 수 있어야한다.

가장 쉬운 방법은 사용자의 Google ID와 Password를 가지고 있으면 된다.
정말 강력하게 모든 권한에 대해 다 접근할 수 있다.
그러나 사용자가 우리의 서비스를 믿을 수 있을까?
많은 사용자들이 같은 ID, PW를 사용하고 그게 유출되는 것일 수도 있다.
그리고 사용자의 ID와 PW를 가지고 있기 때문에 그것이 유출된다면?…
구글이나 페이스북의 입장에서도 신뢰할 수 없는 서비스가 사용자들의 ID와 패스워드를 가지고 있으면 불안하기 마찬가지다.

이 때, 필요한 것이 OAuth이다.

구글이나 페이스북 등에서 accessToken을 발급한다.
이것은 ID나 패스워드가 아니라는 장점이 있고, 나의 서비스가 필요로 하는 부분적인 기능에 대한 권한을 줄 수 있다는 장점 또한 있다.

역할

앞서 소개에서 사용했던 나의 서비스, 유저, 그들의 서비스를 각각 어떤 용어로 부르는지부터 정리한다.

  1. 그들의 서비스, Google이나 트위터(X)나 페이스북 등을 Resource Server 라고 한다.
    우리가 제어하고자 하는 자원을 가지고 있는 서버라는 의미이다.
  2. 유저는 Resource Owner라고 한다.
    우리가 제어하고자 하는 자원의 소유자라는 의미이다.
  3. 우리의 서비스, Denamu는 Client라고 부른다.
    리소스 서버에서 접속하여 정보를 가져간다는 의미이다.
  4. OAuth 공식 문서에는 Authorization 서버라는 역할이 하나 더 있다.
    리소스 서버는 데이터를 가지고 있는 서버이며, Authorization 서버는 인증과 관련된 작업만 처리하는 서버이다. 공식 메뉴얼에서는 두 가지가 구분 되지만 생활코딩 강의에서는 리소스 서버와 인증 서버를 같은 서버라고 생각하고 강의한다.

등록

클라이언트는 리소스 서버를 이용하기 위해 사전에 승인을 받아놓는다. 이것을 등록(Register)이라고 한다.

서비스별로 조금 다를 수 있으나, 공통적으로 Client ID, Client Secret, Authorized redirect URIs 3가지 요소를 가진다.

  1. Client ID
    리소스 서버에서 클라이언트를 식별하는 ID
  2. Client Secret
    Client ID에 대한 비밀번호
    Client ID는 외부에 노출되도 되나, Secret은 노출되면 안된다.
  3. Authorized redirect URIs
    리소스 서버가 권한을 부여하는 과정에서 Authorized Code라는 값을 전달하는데, 이 Authorized redirect URIs로 보내라는 의미.
    이 주소가 아닌 곳에서 요청을 하면 리소스 서버는 무시한다.

실습

  1. 구글 클라우드 플랫폼에 접속한다.
  2. 프로젝트를 하나 만들자.
  3. API 및 서비스를 메뉴에서 클릭하고, 사용자 인증 정보 만들기를 클릭하자.

    OAuth 클라이언트 ID를 클릭한다.
  4. 동의 화면 구성을 누르면 다시 프로젝트 구성 쪽으로 리디렉션된다.
    여기서 양식이 하나 주어지는데 필요한 정보를 모두 입력해주자.
  5. 4번의 작업이 모두 끝나면 아래와 같은 화면이 출력된다.

    OAuth 클라이언트를 만들어보자.승인된 리디렉션 URI 라는 입력창이 있다.
    우리가 학습했던 Authorized redirect URIs에 해당하는 폼이다.
    일단은 강의에서처럼 실습을 위해 http://client.org/callback를 추가하자.

Resource Owner의 승인

이제 등록을 실습해봤으니 승인 과정을 살펴본다.

등록을 하게 되면 리소스 서버와 클라이언트는 등록에서의 3가지 핵심 정보를 알게 된다.
(Client ID, Client Secret, Autorized redirect URL)
클라이언트는 redirect URL에 해당하는 페이지를 구현하고 준비 해놓아야 한다.

리소스 서버가 가진 기능이 만약 A, B, C, D가 있다고 가정해보자.
클라이언트가 B, C에 대한 권한만 필요하다면 최소한의 기능에 대한 인증을 받는 게 서로에게 좋다.
이런 상황에서 어떤 일이 발생하는지 이제 살펴보자.

리소스 오너(유저)는 클라이언트의 애플리케이션에 접속한다.
이 때, 리소스 서버를 사용해야 하는 경우가 발생한다.(페이스북 글 게시, 구글 캘린더 수정 등)
그래서 클라이언트는 리소스 오너에게 페이스북으로 로그인하기 와 같은 화면을 보여줄 것이다.
혹은, 귀하께서 사용하려는 기능을 위해서 페이스북에 xxx와 같은 인증을 필요로 합니다. 같은 메세지를 보여줄 수도 있을 것이다.
무엇이 되었건 간에, 사용자가 동의를 해야만 다음 과정으로 진행할 수 있다.




이런 버튼을 클릭하면 그 동의를 하는 것인데, 이 버튼이 가지는 링크는 다음과 같다.
https://resource.server/?client_id=1&scope=B,C&redirect_uri=https://client/callback
어디서 많이 본 정보들이지 않은가?
클라이언트 아이디, 리다이렉트 uri 그리고 클라이언트에서 필요로 하는 B, C 기능이다.
scope에 대한 내용은 정확하게 B, C인 것이 아니라 구글이나 페이스북 등에서 정해놓은 형식을 따른다.

리소스 오너가 로그인에 성공하면 리소스 서버는 그제서야 클라이언트 id값과 redirect url을 비교해서 유효한 서비스에서 요청한 것인지 확인한다.

만약 클라이언트 id와 redirect url이 다르면 여기서 종료한다.
둘이 같다면 client에서 요청한 기능을 목록으로 보여주면서, 리소스 오너가 B, C에 대한 권한을 클라이언트에게 허용할 것인지 확인하는 과정을 거친다. (네이버나 카카오 로그인으로 배민, 지마켓, 쿠팡 등 쇼핑 플랫폼을 로그인해보면 나오는 그 화면이다.)

리소스 오너가 허용하면 리소스 서버에 허용했다는 정보가 전송된다.
리소스 오너의 id가 1이라고 가정하면, user id가 1인 사용자에게 scope B와 C가 허용되었다는 정보가 DB든 서버 어딘가에 저장이 된다.

Resource Server의 승인

리소스 서버는 승인하기 전에 Authorization code를 먼저 리소스 오너에게 전송한다.
(Location 값으로 [https://client.org/callback](https://client.org/callback)?code=3 처럼 redirect-uri에 code를 쿼리로 넣고 설정한다.)
그러면 리소스 오너쪽에서 해당 주소로 리디렉션 동작이 일어나고, 클라이언트에서 authorization code가 3으로 설정된다.

이제 클라이언트는 리소스 오너를 통하지 않고 직접 리소스 서버와 연결한다.
https://resource.server/token?grant_type=authorization_code&code=3&client_id=1&redirect_uri=https://client/callback&client_secret=2 이런 식으로 authorization code와 client id, client secret, redirect uri 값을 리소스 서버에 전달한다.
리소스 서버는 이런 값들을 가지고 저장된 데이터를 비교해보면서 전부 일치하는지 확인하고 승인 한 뒤 액세스 토큰을 발급한다.

  • 정리
    1. 사용자(리소스 오너)가 클라이언트 애플리케이션을 통해 인증을 시작합니다.
    2. 클라이언트는 사용자를 Auth 서버의 /authorize 엔드포인트로 리다이렉트합니다.
    3. 사용자가 인증하고 권한을 부여하면, Auth 서버는 Authorization code를 생성하여 https://client.org/callback?code=3와 같이 지정된 리다이렉트 URI로 사용자를 리다이렉트합니다.
    4. 클라이언트는 이 코드를 받은 후, Auth 서버의 /token 엔드포인트로 직접 요청을 보냅니다:
    5. POST /token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=3& client_id=1& redirect_uri=https://client.org/callback& client_secret=2
    6. Auth 서버는 정보를 검증한 후 액세스 토큰을 발급합니다.
    7. 클라이언트는 이 액세스 토큰을 사용하여 Resource 서버(이 경우 같은 서버)의 보호된 리소스에 접근합니다.

액세스 토큰 발급

OAuth의 궁극적인 목표는 해당 기능에 대한 권한이 열려 있는 액세스 토큰을 발급받는 것이다.
이제 승인이 끝났으니, Authorization code 값을 리소스 서버에서 삭제한 뒤 액세스 토큰을 생성한다.
여기서는 4라고 가정해보자. (Authorization code는 일회용이며, 승인에서만 사용된다.)

이 4라는 토큰을 이제 클라이언트로 전송하고 클라이언트는 이 값을 DB나 파일 등으로 저장하여 관리한다.

액세스 토큰은 리소스 서버로 하여금 클라이언트에게 user id가 1인 사용자의 유효한 기능 B와 C에 대한 권한이 열려 있다는 것을 보장하고 사용할 수 있도록 도와준다.

API 호출

각각의 서비스(리소스 서버)마다 구현되어 있는 API가 있다.

구글의 경우에는 Authorization에 Bearer 을 설정해서 요청을 보낼 수도 있고,
실제 api 요청 경로에 쿼리스트링으로 access\_token=<access\_token값>으로 사용할 수도 있다.

두 번째 방법은 서비스마다 구현되어 있을 수도 있고 아닐 수도 있으며 첫 번째 방법이 보편적으로 사용되며 더 안전한 방법이다.

리프레쉬 토큰

액세스 토큰에는 만료 기간이 있다. 짧게는 수분, 수십분에서 길게는 30일, 90일까지도 설정할 수 있다. 어떻든 결국에는 만료일이 존재한다.

이렇게 토큰이 만료되었을 때 쉽게 토큰을 발급받기 위해 리프레쉬 토큰이 존재한다.


  1. Auth Grant: 권한을 획득한다, 허가한다는 의미
  2. 액세스 토큰을 그 결과로 발급하는데, 리프레쉬 토큰을 같이 발급해주는 경우가 많다.
  3. 어느날 액세스 토큰을 요청했다가 invalid token 에러가 발생하면 액세스 토큰의 기한이 만료된 것이다.
  4. 그래서 리프레쉬 토큰을 전달하여 다시 액세스 토큰을 전달받는다.
    • 리프레쉬 토큰을 다시 갱신되는 경우도 있고,
      액세스 토큰만 갱신하는 경우도 있다.
    • 리소스 서버마다 이런 방식이 다르기에 메뉴얼을 잘 확인해야 한다.
      • 구글의 경우, 새로운 액세스 토큰을 발급한다.

세 줄 요약

이번 학습 내용을 요약해보면 OAuth는 사용자가 가지는 권한을 세분화하여, 비밀번호 없이도 제3자 애플리케이션이 사용자 계정에 대한 제한된 접근을 가능하게 만든다.
이를 위해 액세스 토큰과 리프레쉬 토큰을 발급하여 사용한다.
그리고 토큰 발급을 위해 Authorization Code Grant 라는 인증 방식을 널리 사용한다. (이외에도 다른 인증 방식이 존재한다.)

추가적으로 학습할 만한 개념

  • OAuth 2.0의 다양한 인증 방식(Grant Types)
    • Authorization Code Grant(현재 설명된 방식)
    • Implicit Grant
    • Client Credentials Grant
    • Resource Owner Password Credentials Grant
  • 보안 관련 고려사항 추가
    • PKCE(Proof Key for Code Exchange) 메커니즘
    • 토큰 보관 방법
    • CSRF 공격 방지를 위한 state 파라미터 활용
  • OpenID Connect와의 관계 언급 (많은 경우 함께 사용됨)

참고 자료

https://www.youtube.com/playlist?list=PLuHgQVnccGMA4guyznDlykFJh28_R08Q-

https://datatracker.ietf.org/doc/html/rfc6749

https://developers.google.com/identity/protocols/oauth2?hl=ko

https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko#node.js_3