오늘 배운 것
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: {
//sdk
googleSocialLogin() {
//auth2 로드
let vm = this;
window.gapi.load("auth2", function() {
//GoogleAuth객체 생성
let gauth = window.gapi.auth2.init({
client_id: process.env.VUE_APP_GOOGLE_CLIENT_ID,
scope: "openid email profile"
});
gauth.then(
//GoogleAuth 초기화 성공
response => {
if (gauth.isSignedIn.get()) {
//만약 로그인이 이미 되어있다면,
//액세스 토큰 반환
console.log(response.Pd.aC);
//액세스 토큰을 서버로 전송 및 응답에 따라 라우팅(구현 예정)
vm.$router.push("/edit");
}
//로그인이 되어 있지않으면
//오프라인 액세스 권한요청
else {
gauth.grantOfflineAccess().then(
//로그인 성공
response => {
console.log(response.code);
//getGoogleRefreshToken 함수를 호출
vm.getGoogleRefreshToken(response.code);
},
//로그인 실패
err => {
console.log(err);
}
);
}
},
//GoogleAuth 초기화 실패
error => {
console.log(error);
}
);
});
},
getGoogleRefreshToken(code) {
//받은 코드를 바탕으로 access_token 및 refresh_token 요청
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)
//psot요청이 성공했을 시
.then(res => {
//서버로 access_token 및 refresh_token 전달(구현 예정)
console.log(res);
//서버응답에 따라서 editpage 혹은 signup로 이동(구현 예정)
this.$router.push("/edit");
})
//post요청이 실패했을 시
.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()같은 라이프사이클 메소드로 받아와야하기 때문에 좀 별로다.