오늘 배운 것
Vue.js에서 Google SDK를 이용해서 Refresh Token 받기
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>
<body>
<div id="app"></div>
//구글에서 제공하는 자바스크립트용 sdk를 사용하기 위해서 script를 불러온다.
<script src="https://apis.google.com/js/platform.js"></script>
</body>
</html>
//Login.vue
<template>
<div>
<div>로그인 페이지입니다.</div>
//버튼을 클릭하면 googleSocialLogin 함수 실행
<button @click="googleSocialLogin">구글 소셜 로그인</button>
</div>
</template>
<script>
import axios from "axios";
import qs from "qs";
export default {
data() {
return {};
},
methods: {
googleSocialLogin() {
let vm = this;
window.gapi.load("auth2", function() {
let gauth = window.gapi.auth2.init({
client_id: process.env.VUE_APP_GOOGLE_CLIENT_ID,
scope: "openid email profile"
});
gauth.then(
response => {
if (gauth.isSignedIn.get()) {
console.log(response.Pd.aC);
vm.$router.push("/edit");
}
else {
gauth.grantOfflineAccess().then(
response => {
console.log(response.code);
vm.getGoogleRefreshToken(response.code);
},
err => {
console.log(err);
}
);
}
},
error => {
console.log(error);
}
);
});
},
getGoogleRefreshToken(code) {
if (code) {
const url = "https://oauth2.googleapis.com/token";
const query = qs.stringify({
code: code,
client_id: process.env.VUE_APP_GOOGLE_CLIENT_ID,
client_secret: process.env.VUE_APP_GOOGLE_CLIENT_SECRET,
redirect_uri: "postmessage",
grant_type: "authorization_code"
});
axios
.post(url, query)
.then(res => {
console.log(res);
this.$router.push("/edit");
})
.catch(err => {
console.log(err);
});
}
}
}
};
</script>
특이점
- https://developers.google.com/identity/sign-in/web/reference에서 구글 gapi 메소드들을 정독하고 시작한다.
- 자바스크립트 SDK를 이용해서 구글 로그인을 진행할 시에 refresh 토큰을 받을 수 없다. 구글에서 권장하는 방식은 클라이언트 단에서 SDK를 이용해서 "authorization_code"를 받은 다음, 이 코드를 서버로 넘겨서 서버에서 refresh 토큰을 얻게 끔 하는 방식을 권장하고 있다.
- 어쩔 수 없이 gauth.grantOfflineAccess() 통해서 "authorization_code"를 받아내고 다시 구글의 /token 엔드포인트로 post요청을 보내서 "access_token"과 "refresh_token"을 받고 있다.
- 결국엔 반쪽짜리 SDK다. SDK + HTTP요청이 반반이니.
- 나는 클라이언트 단에서 "refresh_token"이 필요했기 때문에 이런식으로 어거지로 구현했다. 만약 access_token과 유저정보만 필요한 경우라면 SDK만으로도 구현이 가능하다.
- 이런식으로 구현 할 경우 network 탭에서 요청 header를 살펴보면 client_secret이 그대로 명시되어 있다는 점을 알 수 있다. 보안적으로 취약할 수 밖에 없는 방식이다.(한계점)
- "getGoogleRefreshToken" 함수에서 post요청을 보낼 때 "redirect_uri"에 클라이언트 ID만들 때 적은 "redirect_uri" 적으면 "redirect_uri mismatch" 오류가 뜬다. 그래서 "postmessage"로 바꾸니 정상적으로 요청이 되었다.
- GoogleAuth 프로미스 내에서는 "this"가 vue 인스턴스가 아니다. 메소드 바깥에서 this를 다른 변수에 할당을 해서 사용해야 한다.
- HTTP 요청으로만 구현한 것보다 코드는 좀 더 깔끔한 것 같다. HTTP 요청시 code를 달고 redirect 되는데 그 때 달린 쿼리들이 꽤 더럽고, created()같은 라이프사이클 메소드로 받아와야하기 때문에 좀 별로다.