구글 ID_Token 을 검증하며 알아보는 JWT(feat. Go)

Tei·2021년 1월 8일
7
post-thumbnail

구글 ID_Token 을 검증하며 알아보는 JWT(feat. Go)

여러가지 이유에 의해서 서드파티 로그인을 구현해야 하는 경우가 있습니다.

직접 로그인을 구현하기 귀찮아서일 수도 있고, 혹은 애플처럼 정책에 의해 구현해야할 경우도 있겠습니다.

최근에 갠프에서 구글 로그인을 구현할 일이 생겨서 한번 같이 알아보도록 하겠습니다.

구글 로그인

구글 로그인을 구현하는 방법은 여러가지가 있는데요, 방법이 여러가지다보니 처음 구현하시는 분들이 많이 헷갈려하시는것 같습니다.

보통은 클라이언트 사이드에서 code 를 받아서 리다이렉션URL 로 콜백시키는 방법을 많이 사용하는듯 합니다.

(https://www.joinc.co.kr/w/man/12/oAuth2/Google)

해당 방법은 한글로 된 자료도 많고 잘 정리하신 분들이 많아서, 저는 ID_TOKEN 을 통한 로그인 방식을 한번 소개해드리려 합니다.

플로우

기본적으로 해당 문서의 플로우를 따르고 있습니다.

  1. FE 혹은 앱에서 google 인증 라이브러리를 사용하여 id_token 을 획득합니다
  2. JWT 형태의 id_token 을 서버로 보내 변조되지 않았는지 검증합니다.
  3. 변조되지 않았다면 해당 정보를 믿고 사용합니다.

아주 간단한 플로우로 되어있습니다. 그럼 단계별로 살펴보도록 하겠습니다.

ID_TOKEN 얻기

Google 에서 제공되는 gapi 자바스크립트 라이브러리를 통해 id_token 을 얻습니다.

<script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>

다소 귀찮으시다면 gapi 를 좀더 편하게 쓸 수 있는 gapi-script 라는 라이브러리를 사용하셔도 무방합니다.

저는 다소 귀찮기때문에(...) gapi-script 를 사용해주었습니다.

이렇게 만들어진 버튼을 클릭하면, 구글 로그인 화면이 뜨게 되고, 정상적으로 로그인 되었다면 getAuthResponse 함수를 통해 id_token 을 얻을 수 있습니다. 받은 id_token 을 백엔드 서버로 전송해주시면 됩니다.

이해해야할 영역이 없는것 같아 설명은 생략하도록 하겠습니다.

ID_TOKEN은 무엇인가?

ID_TOKEN 은 JWT (https://tools.ietf.org/html/rfc7519) 형태로 이루어진 구글의 유저 정보입니다.

JWT 가 무엇이고, 왜 사용하는지에 대한 자세한 글은 (https://meetup.toast.com/posts/239) 좋은 글이 있어 이것으로 대체합니다.

서버로 보낸 id_token 의 값을 확인하면 대략 아래와 같은 형태입니다.

eyJhbGciOiJSUzI1NiIsImtpZCI6IjI1MmZjYjk3ZGY1YjZiNGY2ZDFhODg1ZjFlNjNkYzRhOWNkMjMwYzUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiYXpwYmxhaGJsYWguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiJhdWRibGFobGJsYWguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiI4OTg5ODk4OTg5ODk4OTg5IiwiZW1haWwiOiJ0ZWlob25nOTNAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJwdC1kc2thLTJkYWsiLCJuYW1lIjoiVGVpSG9uZyIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vcGljcGljcGljIiwiZ2l2ZW5fbmFtZSI6IlRlaSIsImxvY2FsZSI6ImtvIiwiaWF0IjoxNjEwMDQyMjIyLCJleHAiOjE2MTAwNDIyMjIsImp0aSI6IjgyMjIyMjIxMjMzMmRhc2RhYWFhYWRjIn0.AJ7KtwszbfzRJ6TAB3yzEn1TD9AhVNrM3v532yJcXVF8AGqIfYlr-JQTyD-u5lR8uwse79l9d1s7ualTtErKebBcXz0OJT1R19Cey4UKNs_xFKxQXVEd-TmPBoCzs0GKQxqR4APIu5g71oubcN6PcHeWZAqxr9_Vqx_rzQ2aFQ5G1DE8vX05G9sXot2uXewK_0e2cN8sXdBbUuFTFjyGhOel9u_GUWdIlQfwHiOCdjLn2QD3KBYOMW7KshxW4fYk8dXtWZM5RtcBXCUSd_k-kfJhaBaXQNRUcqkTzAR5kUGqw95Cdj04FVn1uG1BpMYjpsytIZHFqTJhlRQ-YjmRwA"

이 토큰에는, 우리가 필요로 하는 정보가 모두 담겨져있기때문에 바로 디코딩해서 사용하기만 하면 됩니다.

먼저 이 토큰을 한번 json 으로 변경해보도록 하겠습니다.

https://jwt.io/

에서 확인해 본다면,

서드파티 로그인에 필요한 데이터가 잘 들어있는것을 확인할 수 있습니다.

ID_TOKEN 이 변조되지 않았는지 확인하기

데이터를 잘 확인한것은 좋은데, 이 데이터를 믿고 써도 되는지는 아직 확인하지 않았습니다.

해당 토큰이 변조되지 않았는지 확인해 보도록 하겠습니다.

JWT 는 공개키를 사용하여 검증할 수 있습니다. 구글의 공개키는

(https://www.googleapis.com/oauth2/v3/certs) 에서 확인할 수 있습니다.

저희가 발급받은 키의 kid252fc..... 니까 두번째 공개키를 사용하면 되겠습니다.

이 공개키를 사용하여 토큰을 검증하는 절차는 아래와 같습니다.

  1. id_token 의 헤더의 kid 를 확인한다
  2. 구글 공개키(https://www.googleapis.com/oauth2/v3/certs) 에서 kid 가 같은 공개키를 찾는다.
  3. 공개키의 n,e 값을 통해 publicKey를 생성한 후 id_token 의 서명을 검증한다(https://johngrib.github.io/wiki/rsa-encryption).

RSA 라이브러리를 사용해서 직접 공개키를 만들어 검증하는것이 아주 어려운 일은 아니지만, 웬만한 언어에서는 관련한 라이브러리가 존재합니다. golang 의 경우

google.golang.org/api/idtoken 라는 라이브러리가 있기때문에, 이를 사용해서 검증해보도록 하겠습니다.

google.golang.org/api/idtokenValidate 를 사용하여 검증했고, 만약 변조가 있었어서 검증이 제대로 되지 않았다면 err 가 발생하게 됩니다.

그럼 해당 Validate 함수 안에서, 저희가 아까 알아봤던 일들이 정말로 벌어지고 있는지 확인해볼까요?

먼저, 아까 한번 접속해봤던 구글 공개키의 주소가 googleSACertsUrl 변수로 관리되고 있네요.

그리고, 토큰을 헤더, 페이로드, 시그니처로 자른 후 헤더의 알고리즘대로 검증하고 았습니다.

우리 토큰의 알고리즘은 "RS256"이었으니까 validateRS256 함수로 가겠군요.

짜잔 저희의 예상대로, 구글 공개키를 불러와서, 공개키를 만들고, 검증을 시도하고 있네요.

마무리

오늘은 앱이나 웹에서 어떻게 구글 id_token을 얻을 수 있고,

서버에서 공개키를 사용하여 이를 어떻게 검증하는지 알아보았습니다.

다른 기능 없이 딱 서드파티 로그인만 필요한 경우, 가장 간편하고도 강력한 방식이 아닐까 싶습니다.

구글뿐만 아니라, id_token 같은 방식으로 서드파티 로그인을 제공하는 다른 회사들도 같은 방식이니 참고하셔도 좋을 것 같습니다.

변조되지 않았다 라는 사실만으로 인증처리를 할 수 있다는게 언제봐도 재밌네요.

아무리 생각해도 JWT 를 만든 사람은 천재같아요.

도움이 되셨길 바라며 더 좋은 내용으로 다시 찾아오도록 하겠습니다.

profile
Being a service developer

4개의 댓글

comment-user-thumbnail
2023년 1월 10일

안녕하세요 개발공부를 하고 있는 학생입니다! 기존의 인가코드를 받아 백에서 google로 token을 받는 방식과 front에서 직접 jwt를 받는 방식에서 전자에 비해 후자가 접근성 (예를 들어 db접근에 제한이 생긴다던가..)의 문제나 보안적인 이슈를 갖진 않을까요? 사내에서 두 가지 장단점을 비교하며 기술을 사용하려고 하는데 정리가 되지 않아서 여쭤봅니다!!

1개의 답글
comment-user-thumbnail
2023년 5월 8일

백엔드 API 호출시 유저 식별기능 정도로 사용하려는데요

그래도 access token 없이 id token 만 사용해도 보안에 문제 없을까요?

1개의 답글