0auth2.0

OAuth2.0 은 무엇이며 왜 사용하는가?

OAuth 2.0 이란 써드 파티 어플리케이션의 인증을 위한 규약이다.

가령 내가 만든 어플리케이션이 구글의 서비스를 쓰기 위한 다양한 방법이 존재하는데, 대부분의 경우 내가 구글에 가서 인증키를 발급받은 다음에 이 인증키를 어플리케이션 내에 하드코드로 박아 넣는 방식을 사용해 왔다. 이러한 형태의 인증은 매우 흔한데 매우 많은 API 사업자들이 이러한 방식의 인증을 제공한다.

이 경우 해당 키가 탈취되면 매우 심각한 문제가 발생하는데, 해당 키를 가지고 그 어떤 행동도 할 수 있다는 것이다. 이 키는 권한이라는 개념이 없기에 유저의 모든 권한을 가지게 되고 따라서 이 키가 탈취된다는 것은 사용자의 모든 정보가 탈취된 것이라고 봐도 무방하다.

또 요즘과 같이 수많은 API 기반의 IT 서비스가 탄생하고 각 서비스들이 유기적으로 사용되는 경우는 매우 복잡한 인증들이 많이 필요하게 된다. 가령 우리가 흔히 쓰는 업무 툴인 지라만해도 지라에서 나의 구글드라이브에 접근할 권한을 주는 것 처럼 사용자의 특정 서비스에 대한 권한을 위임받는 것은 이제 매우 흔한 것이 되었다.

OAuth 는 이러한 형태의 인증의 새로운 규약을 제공하는데 이번 포스트에서는 내가 만든 어플리케이션이 내 어플리케이션 사용자의 구글 계정에 접근하고 이를 사용할 권한을 할당받아야 하는 경우이다.

일반적으로 생각하면 이를 위해서 가장 편한것은 유저에게 아이디와 비밀번호를 받아 내가 보관하는 것이 있겠다. 사실 개발자 입장에서는 매우 매력적으로 느껴지지만 사실 사용자의 개인정보는 탈탈 털렸고, 나는 사용자의 구글 드라이브의 사진 등 여러 중요 정보에 접근할 수 있을 것이다. 물론 이것은 심각한 상황이고 우리의 고객은 우리를 신뢰하지 않을것이고 신뢰해서도 안될 것이다.

이 경우 괜찮은 방법중 하나는 바로 우리가 “구글에 어떤 구글 유저가 우리에게 구글 API 를 사용할 권한을 주고 싶다던데 의심스러우면 너가 물어봐!” 라고 하는 방법이 있다. 구글이 직접 사용자에게 질문을 하고 사용자가 이를 허가한다면 이는 매우 바람직한 방법이 아닐 수 없다.

이 경우 문제가 하나 있는데 내가 구글에게 매번 사용자에게 물어봐! 라고 한다면 사용자와 구글은 매우 화가날 것이라는 것이다. 내가 사용자의 구글 드라이브를 사용할때마다 사용자에게 구글에게 답변을 해달라고 하는것은 정말이지 성가신 일이다.

그래서 OAuth 는 좋은 해결방법을 생각해 낸다. 바로 사용자가 구글에게 우리를 허가를 해주었다는 인증서를 발급하는 것이다. 이 인증서를 통해 우리는 구글에게 매번 특정 사용자의 권한을 입증할 수 있다. OAuth 에서 이러한 인증서를 access token 이라고 부른다.

하지만 만약 이 인증서가 바뀌지 않는다면 큰 보안 이슈가 있는데, 이 책임은 사실 우리가 져야 할 것이다. 유저는 우리를 믿고 자신의 구글 권한을 부여했는데, 우리가 이를 제대로 보관하지 못했기 때문이다. 여기서 좋은 해답이 하나 있는데 인증서가 계속 만료되게끔 하여 탈취되어도 보다 안전하게 하고 우리가 이를 갱신할 수 있는 별도의 인증서를 보관하는 것이다. 물론 이 인증서도 탈취될 수 있지만 구글은 이 인증서와 우리의 비밀번호를 받아 이를 인증하기 때문에 이것이 해킹당하려면 해커는 인증서를 갱신할 수 있는 토큰 (refresh token) 과 우리의 client secret 두가지를 모두 탈취해야 할 것이다.

따라서 OAuth는 이러한 문제를 잘 해결해 준다.

Google API 사용을 위한 OAuth 인증 절차

Google API 에서 OAuth 인증 절차는 다음과 같다.

구글에서 Client ID 와 Client Secret 를 매뉴얼하게 발급받는다. (이는 google api console 에서 할 수 있다.)

이 Client ID 는 나에게 부여되는 공유 번호이고, secret 으로 이를 증명할 수 있다.

우리는 구글에게 어떤 사용자의 권한을 원한다고 요청을 하면 구글은 자신이 만든 별도의 인증페이지로 고객을 보내고 고객이 여기서 자신이 맞다고 하면, 그 인증으로 authentication code 을 발급하여 우리가 전달한 redirect uri 로 요청을 보내준다. 우리는 이 token 을 구글에게 전달해서 access token 과 refresh 토큰을 발급할 수 있는 것이다.

이를 코드로 작성해 보자

먼저 구글에게 우리의 client id 와 원하는 권한의 범위를 정해서 전달한다.

1
2
3
4
5
https://accounts.google.com/o/oauth2/v2/auth?\
scope=https://www.googleapis.com/auth/analytics&\
redirect_uri=http://localhost:8080&\
client_id=<YOUR_CLIENT_ID>&\
response_type=code

여기서 query parameter 를 한번씩 살펴보면

scope : 어떤 resource 에 대한 권한을 받을 것인가

redirect_uri: 구글이 유저에게 확인을 한 뒤에 어디로 요청을 반환해줄 것인가

response_type: code 라고 써줘야 한다 뭔지 모름…

client_id: 내 어플리케이션이 발급받은 client id

사용자의 요청을 받아 저렇게 구글에 전달하면 구글은 별도의 prompt 를 띄워서 사용자에게 구글 계정을 인증할 것인지를 직접 묻게 된다. 사용자의 요청은 구글에게 전달이 되고, 구글은 사용자의 인증이 완료되면 위에서 우리 어플리케이션이 알려준 redirect_url 로 사용자의 authentication token 을 전달해 준다. 이 code를 다시 아래와 같이 우리의 client secret 과 함께 구글에 보내주면 우리는 비로소 access token 과 refresh token 을 발급받을 수 있다.

여기서 주의해야할 점은 redirect_url 에 명시된 호스트에서 응답을 받을 준비를 하고 받은 authentication code 를 다시 구글에 보내 access token 과 refresh 토큰을 발급해야 한다는 것이다.

1
curl +X POST <https://oauth2.googleapis.com/token?code=><당신의 인증 코드>&client_id=<당신의 클라이언트 아이디>&client_secret=<당신의 클라이언트 secret>&redirect_uri=http://localhost:8080&grant_type=authorization_code

code: authentication code

client_id: id of the application client

client_secret: you secret

redirect_uri

grant_type: hard code authorization_code which represents grant type

redirect_url 의 서버가 사용자의 authentication code 를 받아 위 요청을 보내면 access_token 과 refresh token 을 발급받을 수 있다.

추후에 access_token 이 만료된다면 refresh token 으로 아래처럼 새로운 access_token 을 발급받을 수 있는데 이를 통해 우리는 사용자에게 매번 구글 인증을 하도록 하지 않고 별도의 refresh 토큰을 잘 보관해두고 만료된 access_token 을 필요할 때마다 갱신해 줄 수 있다.

1
2
3
4
5
6
7
8
curl -X POST \\
<https://oauth2.googleapis.com/token> \\
-H 'Content-Type: application/x-www-form-urlencoded,multipart/form-data;' \\
-H 'content-type: multipart/form-data
-F client_id=client_id \\
-F client_secret=client_secret \\
-F refresh_token=refresh_token \\
-F grant_type=refresh_token

이렇게 발급받은 토큰을 Header 에 Authorization Bearer 방식으로 담아 보내면 우리는 드디어 구글 API 를 사용할 수 있게 된다!!

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×