user가 Github을 통해서 웹사이트로 다시 redirect 하게 한다.
2. Users are redirected back to your site by GitHub
https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
지금 현재 프로젝트 웹사이트를 보면 로딩하고 있다. URL
이 Router
에 존재 하지만
Controller
의 응답이 없으면 브라우저는 영원히 로딩 될거다.
그래서 무언가 조치를 취해줘야 한다. 일단 Github
에서 받은 토큰을 Access
토큰으로 바꿔 줘야한다.
Github
에서 준 코드를 Access
토큰으로 바꿔 보도록 한다.
우선 다음과 같은 parameter
들과 함께 POST
요청을 보내야 한다.
client_id
는 어디에 있는지 알고 있다. client_secret
는 절대 프론트엔드로 가지 않을거다.
그리고 code
가 있다. 전부 다 가지고 있다. code
는 URL
에 있고
client_id
는 여기 있고,
Client ID
2c44ee26963db98266d4
client_secret
는 말 그대로 비밀이다.
보다시피 벌써 client_id
를 2번씩이나 썼다. client_id
를 .env
파일에 두는게 좋을 것 같다.
COOKIE_SECRET=asdlfjaslkdfj12345136356aljga
DB_URL=mongodb://127.0.0.1:27017/wetube
GH_CLIENT=2c44ee26963db98266d4
client_id
를 .env
에 저장하는 이유는 client_id
가 어떤 비밀이라서가 아니다.
어차피 요청시 URL
에 client_id
가 보여질건데 비밀로 할 이유는 없다.
이렇게 하는 이유는 값을 한 장소에 넣음으로서 어디서든지 값을 사용 할수 있게 하기 위해서이다.
그러고 이 부분을 process.env.GH_CLIENT
로 바꿔 준다.
export const startGithubLogin = (req, res) => {
const baseUrl = "https://github.com/login/oauth/authorize";
const config = {
client_id: process.env.GH_CLIENT,
allow_signup: false,
scope: "read:user user:email",
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
return res.redirect(finalUrl);
};
그리고 다음 단계로는 client_secret
이 필요하다. 이건 오로지 백엔드에만 존재해야 되는 secret
이다.
저번에도 봤다시피 client_id
는 URL
에 보여지기 때문에 user
가 client_id
를 볼수 있다.
이건 별로 중요하지 않기에 상관없다. 하지만 secret
는 코드 어디에서든 보여져선 안된다.
다시 .env
로 돌아가서
COOKIE_SECRET=asdlfjaslkdfj12345136356aljga
DB_URL=mongodb://127.0.0.1:27017/wetube
GH_CLIENT=2c44ee26963db98266d4
GH_SECRET=
보안상 시크릿 코드는 올리지 않았다. 아무도 알아선 안되기때문이다.
이제 GH_SECRET
이 생겼다. 또 다른 config
객체를 만들어 본다.
export const finishGithubLogin = (req, res) => {
const config = {
client_id: process.env.GH_CLIENT,
client_secret: process.env.GH_SECRET,
code: req.query.code,
};
console.log(config);
};
client_id
를 다시 보내줘야한다. client_secret
과 code
도 보내준다.
그리고 code
는 URL
에 보이는 code
를 쓰면 된다. 그러면 req.query.code
가 된다.
콘솔창에 출력해서 config
가 작동하는지 확인한다.
{
client_id: '2c44ee26963db98266d4',
client_secret: ,
code: '4c93d155f5ea706da00e'
}
잘 작동한다. 이제 이것들을 URL
로 다시 집어 넣어야 한다.
왜냐하면 또 다른 request
를 보내야 하기 때문이다.
이 parameter
를 가지고 POST request
를 해본다.
"https://github.com/login/oauth/access_token"
userController.js
에서
export const finishGithubLogin = (req, res) => {
const baseUrl = "https://github.com/login/oauth/access_token";
const config = {
client_id: process.env.GH_CLIENT,
client_secret: process.env.GH_SECRET,
code: req.query.code,
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
};
바로 전과 똑같은 로직을 짜준다. 하지만 이 경우에는 redirect
를 하지 않는다.
POST requetst
를 보내기만 할거다.
vanillaJS
에서 사용했던 fetch
를 기억해 본다.
무언가를 하고 싶거나 무언가를 가져오고 싶을때 사용한다.
지금은 POST
를 쓰고 있다. URL
에 뭔가를 보내야 하기 때문이다.
export const finishGithubLogin = async (req, res) => {
const baseUrl = "https://github.com/login/oauth/access_token";
const config = {
client_id: process.env.GH_CLIENT,
client_secret: process.env.GH_SECRET,
code: req.query.code,
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
const data = await fetch(finalUrl, {
method: "POST",
headers: {
Accept: "application/json",
},
});
const json = await data.json();
console.log(json);
};
그래서 fetch(finalUrl,)
쓰고 method
는 POST
가 되어야 한다.
아직 코드를 저장하지 않는다. 왜냐하면 fetch
에는 then
같은 것들이 있어야 한다.
대신 const data = await
를 추가해 준다.
그리고 JSON
을 가져 올거다. const json = await data.json();
을 써주고
json
을 console.log
해준다.
vanillaJS
에서 fetch
를 이미 사용했었다.
(날씨 지도를 가져오기도 하고 여러가지를 했었다.)
다시한번 복습해보면 사용할 baseUrl
이 있고 configuration
객체도 만들었다.
configuration
객체는 여기 있는 parameter
를 가져야 한다.
client_id
client_secret
이것들 이다.
그리고 나서 Github
가 주는 code
를 사용했다.
URL parameter
도 만들었고 baseUrl
과 parameter
를 합쳐서 finalUrl
도 만들었다.
그리고 finalUrl
에 POST
요청을 보낼거다.
우선 fetch
를 통해 데이터를 받아오고 그 데이터에서 JSON
을 추출 할거다.
그리고 JSON
을 return
을 받기 위해서
Accept: application/json
이걸 보내야 한다.
이걸 보내지 않으면 Github
는 text
로 응답 할거다.
JSON
이 필요하니깐 headers
안에다가 넣어준다. 그리고 string
형태로 바꿔 준다.
이제 URL
에 POST request
를 보내준다. 그리고 몇개의 데이터를 받아보도록 한다.
브라우저를 새로고침을 해본다. 하지만 에러가 난다.code
가 이미 만료가 되었기 때문이다.
code
의 유료기간은 10분 밖에 안된다.
fetch
가 동작하지 않는건 브라우저에서만 사용 가능하다.
inspect
를 해보면 fetch
를 사용 할수 있다. 그러면 작동해야 하는데
문제는 fetch
기능이 NodeJS
에는 포함되어 있지 않다는 거다.
현재 자바스크립트를 쓰고 있어도 function
이 똑같지는 않다.
그 둘은 같지 않다. 어떤건 브라우저에서 안되고 어떤 건 NodeJS
에서 안된다.
예를 들어서 프론트엔드에서 alert
를 사용해 보면 정상적으로 작동한다.
NodeJS
에서도 alert
가 작동을 하는가 보면 에러가 발생한다.
왜냐하면 alert
는 정의되지 않은 함수이다. 이건 다음 파트에서 손 보기로 한다.
그리고
await
를 쓰고 싶다면 꼭async
를 써야한다.
async
를 쓰지 않으면 await
는 작동 하지 않게 된다.
async
와 await
는 항상 같이 붙어 다닌다는걸 기억한다.
다음 파트에서 백엔드에서 어떻게 fetch
를 쓰는지 알아본다.
왜냐하면 fetch
는 굉장히 도움이 많이 된다.
백엔드에서 alert
는 할 필요 없더라도 fetch
를 쓸일은 있다.