Technology/Web

OAuth 2.0를 통한 인증과 인가(Feat. Github, Spring boot)

ikjo 2022. 6. 15. 01:43

인증과 인가

인증(Authentication)이란 무엇일까? 인증은 "사용자가 자신이 누구인지 증명하는 것"이라고 볼 수 있다. PC방을 예로 들어보자. 해당 PC방에서는 밤 10시 이후에는 만 19세(성인) 미만의 청소년 등은 PC방 서비스를 이용할 수 없다는 조건이 있다고 한다. 이때 밤 10시가 되면 현재 이용하고 있는 사람들과 밤 10시 이후에 PC방 서비스를 이용하러 온 사람들은 자신이 성인인지를 입증해야 하는 작업이 필요할 것이다. 이러한 작업을 인증이라고 할 수 있는 것이다. 이를 웹에서 적용해본다면 일례로 로그인을 생각해볼 수 있다. 로그인은 사용자가 자신이 서버에 등록된 회원임을 증명하는 작업 즉, '인증'인 것이다.

 

반면, 인가(Authorization)란 인증을 통해 조건에 부합하는지 확인된 사용자가 어떤 행위를 할 수 있는지 파악하는 것이다. (인가는 인증 이후에 이루어진다.) 앞서 든 예시에 이어서 해당 PC방에서 신분증 등으로 인증 작업을 통과한 사람들의 경우 정책상 밤 10시 이후로 PC방 서비스를 이용할 수 있는 것을 확인할 수 있는데, 이를 인가라고 할 수 있는 것이다. 웹에선 로그인을 통해 인증된 사용자가 어떠한 자원(Resource)에 접근할 수 있는지 확인하는 절차가 이에 해당된다.

 

※ 인증을 '사용자의 신원을 확인하는 절차'로, 인가를 '사용자의 권한을 확인하고 허가하는 절차'로 볼 수도 있다.

 

OAuth란?

앞서 인증과 인가라는 것에 대해 알아보았다. 또한 그에 대한 예시로서 로그인이라는 것을 알아보았는데, 이는 사용자와  서버간 1:1로 이루어지는 인증과 인가 작업이다. 하지만 웹 서비스를 운영하다 보면 사용자의 특정 서버(네이버, 카카오, 깃허브, 구글 등) 즉, 제 3자 서버의 일부 리소스에 접근하고싶을 때가 있다.

 

예를 들어, 숙소 예약 서비스를 운영하고 있다고 가정해보자. 이때 어떤 사용자가 숙소 예약을 완료했는데, 사용자가 상당히 자주 이용하는 서비스(예를들어, 네이버, 카카오 등)의 일정 관리란에 해당 숙소 예약 정보를 표시하고싶은 것이다. 즉, 제 3자의 서버에 리소스에 접근하고 싶은 것이다. 그렇다면 사용자가 해당 일정을 주기적으로 확인할 수 있는 등 서비스 만족도를 느낄 수 있을 것이다. 결과적으로 숙소 예약 서비스 운영진과 사용자 서로가 윈윈할 수 있다.

 

이를 가능하게 해주는 것이 OAuth이다. OAuth는 Open Authorization의 약어로 웹 서버가 사용자 대신 제 3자 서버(사용자가 이용하고 있는 서비스 중 하나)의 보호된 리소스 일부에 접근할 때 사용되는 기술이며, 단순히 1:1로 이루어지는 회원가입 및 로그인과 달리 다른 서비스(네이버, 카카오 등의 제 3자 서버)들과의 연합을 통해 사용자를 식별하는 인증 체계이다.

 

 

OAuth 역할 관련 용어 정의

우선, OAuth를 다루기에 앞서 인증 체계 속 각 역할 주체에 대한 용어를 정리할 필요가 있다.

 

  • resource owner: 보호된 리소스에 대해 접근 권한을 부여할 수 있는 독립체(사용자)
  • client : 리소스 소유자(resource owner)를 대신하여 보호된 리소스를 요청하는 애플리케이션
  • resource server: 보호된 리소스에 대한 client의 요청을 수락하고 보호된 리소스를 호스팅(hosting)하는 서버
  • authorization server: 리소스 소유자가 인증을 거친 후 client에 액세스 토큰(Access Token)을 발급하는 서버

 

rfc6749에 나온 용어 정의를 나름대로 번역해보았지만 제대로 와닿지 않을 수 있다...😂 정말 간단하게 앞서 들었던 예시를 기준으로 나타내자면 리소스 오너(resource owner)는 사용자를, 클라이언트(client)는 숙소 예약 서비스를 제공하는 서버를, 리소스 서버(resource server)와 인증 서버(authorization server)는 사용자가 자주 이용한다고 했던 서비스(예를들어, 네이버, 카카오 등)의 서버인데, 리소스를 관리하는 서버와 인증을 담당하는 서버가 각각 있는 것이다.

 

 

OAuth 인증 체계 흐름도

 

 

OAuth의 인증 방식에는 여러가지 방식이 있는데, 대표적으로 인증 코드(Authorization Code)를 이용한 방식이 있다. 이번 글에서는 인증 코드 방식을 통한 인증 체계에 대한 흐름에 대해 다음의 예시를 통해 간단하게 다루고자 한다. 대략적인 흐름도는 위와 같다.

 

상황 예시 설명

Client는 회원들에 대한 정보를 별도로 관리하지 않는다. 하지만 특정 작업에 대해서는 Client의 회원이라는 인증 과정을 거친 사용자(Resource Owner)들에 대해서만 허용하길 원한다. 이를 위해 나름대로 신뢰할 수 있는 깃허브의 OAuth 인증 체계를 이용하기로 했고, 사용자의 깃허브 일부 리소스에 접근하여 이를 통해 해당 사용자를 검증하고자 한다.

 

1 ~2. Resource Owner ↔ Client

이 단계에서는 Resource Owner가 Client에 접속하여 특정 서비스를 이용하는 중에 Client로부터 해당 서비스는 인증이 필요하다는 메시지를 받았고, Client는 해당 Resource Owner에 대해 인증 처리를 위해 Resource Owner에게 깃허브 연동 로그인을 요청하고 있다.

 

3~4. Resource Owner ↔ Authorization Server

Resource Owner(이하 '리소스 오너')는 Client(이하 '클라이언트')의 요청에 따라 깃허브 Authorization Server(이하 '인증 서버')로 접속하여 인증(로그인)을 하고 클라이언트가 본인의 특정 리소스에 접근해도 되는지에 대한 설명을 듣고 이에 동의하고 있다. 이후 인증 서버는 리소스 오너에게 인증 코드와 함께 당초 클라이언트가 등록했던 콜백 URL로 리다이렉트 응답한다.

 

5. Resource Owner Client

리다이렉트에 의해 리소스 오너는 클라이언트에 다시 접속하게 되고 클라이언트는 쿼리 스트링으로 전달받은 인증 코드를 추출하여 깃허브 인증 서버로부터 액세스 토큰을 요청할 준비를 한다.

 

6~7. Client ↔ Authorization Server

클라이언트는 앞서 리소스 오너로부터 전달받은 인증 코드와 클라이언트 아이디 및 시크릿을 깃허브 인증 서버에 전송하여 액세스 토큰 발급을 요청한다. 인증 서버는 이를 받아 검증한 후 클라이언트에 액세스 토큰을 발급해준다.

 

8~9. Client ↔ Resource Server

본격적으로 클라이언트는 액세스 토큰을 통해 깃허브 Resource Server(이하 '리소스 서버')에 리소스 오너의 특정(앞서 별도 scope에 범위 지정) 리소스를 요청하고 리소스 서버는 이를 검증한 후 클라이언트에 해당 리소스를 응답해준다.

 

10~11. Client  Resource Owner

클라이언트는 해당 리소스를 통해 리소스 오너에 대해 인증 처리를 진행하고 로그인이 처리되었다는 메시지를 응답해준다.

 

 

클라이언트 등록하기

앞서 특정 상황에 대한 깃허브 OAuth 인증 체계의 흐름을 다루어보았다. 하지만 이러한 일련의 작업들이 수행되기 전에 클라이언트는 리소스 오너 대신에 깃허브 리소스에 접근하려는 자기 자신에 대해 깃허브에 등록하는 작업을 해야 한다. 이 과정에서 클라이언트 아이디 값과 시크릿 값을 발급받을 수 있다. 아래와 같이 [오른쪽 상단 프로필 사진 클릭] → [Settins] → [Developer settings] → [OAuth Apps]에 접속한다.

 

 

이후 다음과 같은 화면이 나오는데, "New OAuth App"을 클릭한다.

 

 

이제 다음과 같은 입력창이 나오는데, 어플리케이션의 이름홈페이지 URL, 그리고 앞서 인증 체계 흐름도 3~5번에 등장했던 Callback URL을 필수적으로 작성하여 등록해준다. (Callback URL은 리소스 오너가 인증 동의를 한 이후 인증 코드와 함께 리다이렉트될 클라이언트의 URL이다.)

 

 

등록을 마친 후에 보여지는 화면에서 주목해야할 부분이 있다. 클라이언트 아이디와 클라이언트 시크릿 값이다. 클라이언트 아이디는 추후 리소스 오너가 인증 서버에 접속할 때 및 클라이언트가 인증 서버에 액세스 토큰을 발급받는 과정 등에서 쓰이는데, 노출되도 보안상 큰 문제가 되지 않는다.

 

하지만 클라이언트 시크릿 값이 노출되면 보안에 문제가 생긴다. 이 시크릿 값은 클라이언트가 인증 서버로부터 인증을 받을 때 사용되며 오직 인증 서버와 클라이언트 둘만이 아는 값이다. 이를 탈취당하면 악용될 우려가 있으므로 가급적 시스템 환경 변수에 저장하거나 암호화하도록 한다.

 

오른쪽 "Generate a new client secret" 클릭 시 시크릿 값을 발급받을 수 있다.

 

 

리소스 오너 대신 깃허브 리소스 조회를 위한 API 명세서

클라이언트는 깃허브로부터 리소스 소유자 대신 Access Token을 이용하여 깃허브 내 리소스 소유자의 리소스에 접근할 수 있다. 이때 깃허브에서 정한 규칙대로 API를 호출하면 되는데, 아래 사이트를 참고해보면 API 명세들을 통해 사용자 관련 여러가지 정보들에 접근 및 제어가 가능하다는 것을 확인해볼 수 있다.

 

 

GitHub REST API - GitHub Docs

To create integrations, retrieve data, and automate your workflows, build with the GitHub REST API.

docs.github.com

 

예를 들어, 사용자의 이메일을 조회해볼 수 있는데, 깃허브의 경우 공용(public) 메일과 응답을 받지 않는 사설(private) 메일 일을 조회해볼 수 있다. 이와 관련해서 깃허브가 제공하는 API 명세는 다음과 같다.

 

 

위 명세를 보면 HTTP API Method와 URI 그리고 헤더와 파라미터, 응답 예시, 상태 코드 등을 확인해볼 수 있으며, 지정된 방식에 따라 API를 호출할 수 있다. 자세한 내용은 아래 링크를 참고해보자.

 

 

Emails - GitHub Docs

About the Emails API Management of email addresses via the API requires that you authenticate through basic auth, or through OAuth with a correct scope for the endpoint. Many of the resources on this API provide a shortcut for getting information about the

docs.github.com

 

 

OAuth 인증 이후에는?

지금까지 OAuth를 통해 리소스 오너 대신에 제 3자 서버의 일부 리소스에 접근하는 예시를 살펴보았다. 그런데, 그 이후에는? 사실 웹 서버는 stateless하기 때문에 앞서 요청했었던 리소스 오너가 이후에 다시 요청을 한들 해당 리소스 오너를 식별할 수 있는 방법은 따로 없다. 결국에는 세션 등을 통해 리소스 오너별로 상태 유지 관리를 해야하는 것이다.

 

아울러, 이번에 다룬 예시에서는 깃허브 인증 서버로부터 액세스 토큰만 받고 리프레쉬 토큰은 받지 않았는데, 액세스 토큰의 경우 기본적으로 8시간 유효하기 때문에 그 이후에 다시 리소스 서버에 접근이 불가능하다. 이를 위해 리프레쉬 토큰을  통해 기존 액세스 토큰의 유효기간을 늘릴 수도 있다.

 

참고로 여기 OAuth에서 다루는 액세스 토큰과 리프레쉬 토큰과 JWT에서 다루는 액세스 토큰과 리프레쉬 토큰은 명칭과 역할은 비슷하지만 용도가 다름에 유의하자. JWT는 앞서 언급했던 상태 유지 관리 기술인 세션의 단점을 보완하고자 나온 인증 방식으로서 세션과 달리 stateless하다는 특징이 있다. 세션과 JWT의 차이에 대해서는 다음 글을 참고해볼 수 있다.

 

 

왜 굳이 세션 대신 JWT를 이용하는가?

왜 JWT의 장점을 버렸나요? 이번에 마스터즈 코스 과정 숙소 예약 서비스 팀 프로젝트를 진행하면서 미션 요구사항을 지키기 위해 JWT을 통한 로그인 검증 기능을 구현해보았다. 이에 JWT에 대해

ikjo.tistory.com