OAuth 2.0 동작 원리 알아보기
인증을 위한 오픈 스탠다드 프로콜인 OAuth2.0에 대한 조사
2023.09.25
OAuth는 인증을 위한 오픈 스탠더드 프로토콜로,
사용자가 Facebook이나 트위터 같은 인터넷 서비스의 기능을 다른 애플리케이션(데스크톱, 웹, 모바일 등)에서도 사용할 수 있게 한 것이다.
🔷 OAuth
🔶 왜 OAuth 를 사용해야 하는가?
OAuth를 살펴보기 앞서서, 먼저 OAuth가 왜 필요한지를 알아보는 시나리오를 살펴보도록한다.
이 시나리오에는 3가지 참여자가 등장하는데, 각각 다음과 같다.
참여자 | 설명 | 정식 명칭 |
---|---|---|
Application | 개발하고자 하는 서비스 | Client |
User | 그 서비스를 이용하려고하는 사용자 | Resource Owner |
Other Service | 연동하고자 하는 제 3자의 서비스 (Google, Facebook….) | Resource Server (+ Authorization Server) |
예를 들면, 사용자가 어플리케이션에 접속해서 제 3자의 서비스 플랫폼에 로그인을 하거나, 글을 쓰거나 하고싶다고 하자.
이런경우, 사용자가 직접 글을 쓰는것이 아닌, 개발중인 서비스가 대신하여 그 행위를 해야하는 것이므로,
사용자로부터 그 사용자가 사용하고 있는 제 3자의 서비스에 대한 접근할 수 있도록 허가를 받아야만 한다.
생각을 아예 안하고 가장 쉬운 방법은, 사용자로부터 아이디
와 비밀번호
를 직접 받아와 그 서비스를 대리로 이용하는 것이다.
그러나 이런 방법은 당연히 보안상의 이슈로 적용할 수가 없다!
그럼 어떻게 개인정보의 공유 없이 이러한 문제를 해결 할수가 있을까?
그때 사용하는 것이 바로 OAuth이다.
OAuth를 이용하면, Access Token을 통해 훨씬더 안전하게 어플리케이션과 제 3자의 서비스간 연동을 구축할 수 있다.
Access Token은 제 3 서비스에서 발행하는 일종의 임시 비밀번호와 같은데,
이 Access Token을 이용하면 다음과 같은 2가지 장점이 있다.
📌 Access Token을 사용했을 때의 장점
Access Token은 사용자의 아이디와 비밀번호가 아니다.
Access Token을 통한 접근은 해당 서비스에서 제공하는 모든 기능이 아니라 어플리케이션에서 필수적으로 필요한 기능만 허용한다.
OAuth를 통해 사용자는 최초에 제 3자의 서비스에 (ID와 PWV로) 로그인을 하면 임시 코드를 부여받고,
받은 임시 코드를 Client에게 알려주게 된다. 그러면 Client는 임시코드를 통해 Access코드를 받아오고,
해당 Access Token을 기억했다가 그 AccessToken을 통해서 그들의 서비스에 접근한다.
🔷 OAuth 동작 과정
🔶 Resource server에 등록 (사전 작업)
Client가 Resource server를 이용하기 위해서는 Resource server의 승인을 사전에 받아두어야 하며, 이틀 Register(등록)라고 한다.
이 등록 방식의 경우 플랫폼마다 다르지만, 공통적으로 Authorized redirect URIs
는 입력해주어야 하며.
Client ID, Client Secret 를 돌려받게 된다.
정보 | 설명 |
---|---|
Authorized redirect URIs | Authorized Code을 돌려줄 URI |
Client ID | 어플리케이션의 고유 식별자. |
Client Secret | 어플리케이션의 고유 시크릿 텍스트 (비밀번호) |
clientiD
의 경우에는 Resource server에서 요청이 들어온
어플리케이션을 식별하기 위한 식별자이기 때문에 외부로 노출되어도 큰 문제는 없지만
client secret
까지 노출 될 경우, 보안 사고로 이어질 수 있기 때문에 노출되지 않도록 특별히 주의해야 한다.
위는 실제로 google cloud console에서 OAuth 클라이언트를 만들었을 때 보이는 화면이다.
Authorized redirect URIs
를 비워두면 안된다는 경고메세지를 볼 수 있다.
🔶 Resource onwner의 승인
위 단계가 끝나면, Resource server와 Client는 모두 Client ID
, client Secret
, Redirect URI
를 알고있게 된다.
이제 준비는 끝났고, 정말 사용자가 이 OAuth를 이용해 무언가 요청을 보낸다고 하자.
만약, Resource owner가 Login 요청을 보낸다면 Client는 사용자에게 여러가지 정보를 담은 링크를 전달하게 된다.
이 링크주소에는 Client ID
, Scope
, Redirect URI
정보가 담겨있다.
예를 들면 다음과 같다.
https://accounts-google.com/o/oauth2/v2/auth?
response_type=code&redirect_uri=[REDIREC_URI]&
scope=https://www.googleapis.com/auth/plus.login&
client_id=[CLIENT_ID].apps.googleusercontent.com
(보기 편하라고 줄바꿈을 넣었는데, 실제로는 한 줄로 입력하면 된다.)
사용자가 이 링크를 열게 되면 흔히 보이는 익숙한 로그인 화면을 보게 된다.
로그인이 성공한다면, Resource server는 링크의 정보 중 client ID 와 같은 값을 가지는 프로젝트를 찾고,
그 프로젝트의 Redirect_URI
와 사용자가 알고있는 링크의 Redirect_URI
가 같은지 확인한다.
만약 다르다면, 여기서 더 진행하지 않고 작업을 끝내버린다.
사용자에겐 redirect_uri_mismatch라는 문구가 보이며 진행이 막히게 된다. (중요)
만약 정상적으로 진행이 된다면, 사용자는 로그인에 성공하게 되고,
Resource server는 사용자의 정보(UserID와 Scope)를 추가하게 된다.
그 후, Authorization code라는 코드를 넘겨주게 되는데, 바로 AccessToken을 넘겨주기 전 사용하는 임시 코드라고 보면 된다.
Resource server는 이 Authorization code를 Redirect URI 링크에 담아 사용자에게 전달하게 된다.
링크를 전달받은 사용자는 해당 링크를 접속해 Client에게 Authorization code를 알려주게 된다.
Authorization code가 무엇인지 알게된 Client는 이를 기반으로 직접 Resource server에 접근하게 된다.
매개 변수 | 설명 |
---|---|
grant_type | OAuth 인증 절차에서 사용되는 인가 유형을 나타내는 매개 변수, 여기서는 authorization_code 를 사용함 |
code | 사용자가 알려준 Authorization code |
redirection_uri | Register(등록)때 Clinet가 Resource server에게 알려줬던 Redirect URI |
client_id | Client가 부여받은 고유 id |
cleint_secret | Client가 부여받은 고유 sceret |
여기서 grant_type에 들어갈 수 있는 값은 크게 4가지가 있는데,
authorization_code
, implictic
, password
, client credential
이 이다.
📌 4가지 Grant type
💠 Authorization Code Grant Type : 권한 부여 코드 승입 타입
Client가 Resource owner 대신 특정 resource에 접근을 요청할 때 사용된다.
접근을 위해 사용자 명과 비밀번호로 Authorization server에 인증을 받고,
권한 코드 (Authorization code)를 함께 활용하여 Access token을 받는 방식
💠 Implicit Grant Tvpe : 암시적 승인 타입
Authorization Code와 다르게 권한 코드 교환 단계 없이
Access token을 즉시 반환받아 이를 인증에 이용하는 방식.
💠 Client Credentials Grant Type : 클라이언트 자격 증명 타입
Client 자체가 Access token을 요청하는 방식. 이 경우 사용자 인증이 필요하지 않음.
💠 Resource Owner Password Credentials Grant Type : 리소스 소유자 암호 자격 증명 타입
Client가 암호를 사용하여 Access token에 대한 사용자의 자격 증명을 교환하는 방식.
여기서는 가장 기본이 되는 Authorization Code 방식을 설명하고 있으므로, grant_type은 authorization_code
로 둔다.
또한 그림에 표현하기가 어려워서 못했는데, 정확히는 Client가 Resource server로 접근할 때 POST요청으로 보내게 된다.
예를 들어, 구글의 경우 https:/oauthz.googleapis.com/token으로 POST요청을 보내게 된다.
grant_type=authorization_code&
code=[CODE]&
redirect_uri=[REDIRECT_URI]&
client_id=[CLIENT_ID].apps.googleusercontent.com
client_secret=[CLIENT_SECRET]
Content-type은 application/x-www-form-urlencoded
로 하고, 한줄로 보내야한다.
(예시에서는 Talend AP라는 크롬 익스텐션을 사용했다)
🔶 Access token 발급
모든 정보가 일치하는것을 확인한 Resource server는, 앞으로 사용할 수 있는 Access token을 발급해주게 된다.
이제부터 Client는 이 Access token 을 헤더에 포함시켜서 Resource server의 API를 호출하면 된다.
Curl -H "Authroization: Bearer <access_token>"
여기서 Bearer는 위 형식에서 Token의 Type에 해당한다.
Token에는 많은 종류가 있고, 서버는 다양한 종류의 토큰을 처리하기 위해 전송받은 Type에 따라 토큰을 다르게 처리한다.
(Basic, Bearer, Digest, HOBA, Mutual, AWS4-HMAC-SHA256 등등)
🔷 정리
아래는 PAYCO 개발자 센터에서 찾은 요약이 잘 된 문서이다.
🔷 📚 추가 자료
🔶Refesh token
기본적으로 Access token은 유효기간이 있어서, 시간이 지나게 되면 다시 발급을 받아야 한다.
하지만 이럴 경우 매번 인증을 하면 불편할 수 있으므로, Refresh token을 사용하기로 한다.
OAuth2.0 에 대한 RFC문서를 보면, 이 과정이 상세히 나와있다.
(A),(B)에서 Access Token과 Refresh Token을 받게 되는데,
Client는 Access Token을 계속 사용하다가, Invalid Token Error가 발생하면,
Refresh token을 이용해 별도의 과정 없이 Access token을 다시 발급받을 수 있다.
RFC 문서에서 (H)에 대한 설명을 보면,
The authorization server authenticates the client and validates the refresh token, and if valid, issues a new access token (and, optionally, a new refresh token).
권한 부여 서버는 클라이언트를 인증하고 새로 고침 토큰의 유효성을 검사하며 유효한 경우 새 액세스 토큰(및 선택적으로 새 새로 고침 토큰)을 발급합니다.
선택적으로 Refresh token도 재발급하는 경우가 있다.
📚 참고자료: JWT에서-Refresh-Token은 왜-필요한가
🔶 OAuth 1.0과 OAuth2.0의 차이
OAuth 1.0과 OAuth2.0은 모두 인증 방식을 표준화한 것이며, Resource owner, Resource server, Client의 상호작용으로 구성된다.
OAuth 1.0 은…
- 구현이 복잡하다.
HMAC
(keyed-hash message authentication code, hash-based message authentication code)를 통한 암호화를 하는 번거로움이 있다.- 인증토큰이 만료가 되지 않아 토큰을 만료하려면 제공자 애플리케이션의 비밀번호를 바꿔야 한다.
OAuth2.0 은…
- 기능의 단순화, 기능과 규모의 확장성 등을 지원하기 위해 만들어졌다.
- https를 통해 암호화를 하여 과정의 단순화 하였다.
- 다양한 인증 방식이 제공된다.
- api서버에서 인증서버와 리소스 서버가 분리됐다.