소셜 로그인을 구현하려 이것저것 알아보면서 깨달은 것은 내가 지금까지 굉장히 단순한 방법으로 소셜로그인을 이해하고 구현해왔다는 것이었다.
지금까지의 내가 생각하고 있던 소셜 로그인의 플로우는 다음과 같다.
토큰 발급을 위한 인증 코드 요청 -> 토큰 발행 -> 토큰으로 사용자 정보 요청 -> 로그인 또는 회원가입
하지만 여기서 빠진 점은 바로 토큰 유효성 검증이다.
프론트에서 access token을 얻어 백엔드 서버에 전달해주고, 백엔드 서버는 이를 이용해 사용자 정보를 요청한다고 할 때, 백엔드에서는 이 토큰이 올바른 키로 서명이 되었는지 등 유효성을 확인 해야한다. 이전에 프로젝트할 때처럼 검증 과정 없이 바로 사용자 정보 요청으로 넘어가면 안된다는 것이다.
(지금부터의 설명은 카카오, 구글, 애플 소셜 로그인을 바탕으로 설명하고 있으니 참고바란다.)
토큰 유효성 검사를 하는 방법은 크게 두가지 방식이 있다.
첫번째는 id_token
을 이용하는 방법이고, 두번째는 access_token
을 이용하는 방법이다.
보통 토큰을 요청하면 서드파티 로그인 서버는 id_token, access_token, refresh_token 이 세가지의 토큰을 준다.
access_token은 각 서버에서 제공하는 API에 접근할 때 사용하는 토큰이고, refresh_token은 access_token을 재발급하고자 할 때 필요한 토큰이다.
이때 id_token은 사용자의 인증인가가 이루어지는 OpenID Connect 프로토콜에서 사용되는 토큰이다. 이 토큰은 JWT이며 사용자 인증에 대한 기본적인 정보들(유저 고유 id, email 등)을 포함한다. (자세한 설명은: what is id_token google oauth)
여기서 주목해야할 점은 id_token은 JWT라는 것이다. 따라서 우리가 디코딩해볼 수 있으며 디코딩하여 얻은 페이로드 값으로 토큰 유효성 검증은 물론 사용자 정보를 얻을 수도 있다.
다음은 구글에서 발행한 id_token을 디코딩한 모습이다.
{
"alg": "algorithm",
"kid": "key_id",
"typ": "JWT"
}
{
"iss": "https://accounts.google.com",
"azp": "",
"aud": "",
"sub": "12341234",
"hd": "myapp.com",
"email": "aaa123@gmail.com",
"email_verified": true,
"at_hash": "Vy-QhQ-v",
"name": "name",
"picture": "https://blahblah",
"given_name": "given_name",
"family_name": "family_name",
"locale": "ko",
"iat": 1660060000,
"exp": 1660070000
}
이 페이로드의 모든 요소에 대해 명확히 이해하고 있는 상태는 아니라, 이 중 몇 개만 설명하자면 다음과 같다.
여기서 kid 값이 서버의 공개키가 맞는지 확인을 통해 토큰 유효성 검증을 할 수 있다. 이 부분은 나중에 더 다루도록 하겠다.
이렇게 id_token으로 유효한 토큰임이 확인되었다면 이 토큰으로 사용자 정보 요청 또는 id_token내의 사용자 정보를 이용하여 회원가입 및 로그인을 처리하면 된다.
두번째로 access_token으로 토큰 유효성 검사를 할 수도 있는데, 카카오나 구글의 경우 엑세스 토큰의 유효성을 판단할 수 있는 API를 제공하고 있다. 따라서 헤더에 검증하고자하는 access_token을 담아 API 요청을 보내어 status code가 200임이 확인되면 토큰이 유효하다는 의미이다.
이 방법은 토큰 검증을 구현하지 않아도 특정 endpoint로 요청을 보내면 되기 때문에 구현하기가 매우 쉽다. 다만 토큰 유효성을 판단하기 위해 외부 서버와의 통신이 일어난다는 점이 단점이다. 실제 로그인이 활발하게 일어나는 서비스인 경우 유효성 검증, 사용자 정보 조회마다 서버와 통신한다면 엄청난 부하가 발생할 것이다. 실제로 구글 공식문서에서는 이러한 이유로 엔드포인트 호출을 통한 토큰 검증을 권장하지 않는다.
애플에서는 아예 토큰 검증 시 필요한 public key를 얻을 수 있는 API만 제공하고 있기도 하다.
이렇게 소셜 로그인 시 외부 서버에서 발행한 토큰을 검증하는 방법에 대해 간단하게 정리해보았다.
아직은 공식문서를 읽는게 좀 힘들다보니, 이런 부분에 대해 이해가 덜 되어있는 상태였던 것 같다. 수많은 서치를 통해 해당 내용을 알게되고 문서를 다시 확인해보니 그동안 대체 무슨 말인가 했던 부분이 이해가 되기 시작했다 ㅋㅋ 나처럼 플로우에 대해 이해가 힘들었던 분들에게 도움이 되었기를 바라며 다음에는 서버의 공개키로 id_token을 검증하는 방법에 대해 정리를 해봐야겠다. (사실 나도 아직 안해봄)
참고
How can I verify a Google authentication API access token?
Sign in with Apple Tutorial, Part 3: Backend – Token verification