Github Login #03

0_cyberlover_0·2022년 4월 20일
0

Node.JS #05

목록 보기
3/19

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

지금 현재 프로젝트 웹사이트를 보면 로딩하고 있다. URLRouter에 존재 하지만

Controller의 응답이 없으면 브라우저는 영원히 로딩 될거다.

그래서 무언가 조치를 취해줘야 한다. 일단 Github에서 받은 토큰을 Access 토큰으로 바꿔 줘야한다.

Github에서 준 코드를 Access토큰으로 바꿔 보도록 한다.

우선 다음과 같은 parameter들과 함께 POST요청을 보내야 한다.

client_id는 어디에 있는지 알고 있다. client_secret는 절대 프론트엔드로 가지 않을거다.

그리고 code가 있다. 전부 다 가지고 있다. codeURL에 있고

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가 어떤 비밀이라서가 아니다.

어차피 요청시 URLclient_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_idURL에 보여지기 때문에 userclient_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_secretcode도 보내준다.

그리고 codeURL에 보이는 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,)쓰고 methodPOST가 되어야 한다.

아직 코드를 저장하지 않는다. 왜냐하면 fetch에는 then같은 것들이 있어야 한다.

대신 const data = await를 추가해 준다.

그리고 JSON을 가져 올거다. const json = await data.json();을 써주고

jsonconsole.log 해준다.

vanillaJS에서 fetch를 이미 사용했었다.

(날씨 지도를 가져오기도 하고 여러가지를 했었다.)

다시한번 복습해보면 사용할 baseUrl이 있고 configuration객체도 만들었다.

configuration객체는 여기 있는 parameter를 가져야 한다.

client_id client_secret 이것들 이다.

그리고 나서 Github가 주는 code를 사용했다.

URL parameter도 만들었고 baseUrlparameter를 합쳐서 finalUrl도 만들었다.

그리고 finalUrlPOST 요청을 보낼거다.

우선 fetch를 통해 데이터를 받아오고 그 데이터에서 JSON을 추출 할거다.

그리고 JSONreturn을 받기 위해서

Accept: application/json 이걸 보내야 한다.

이걸 보내지 않으면 Githubtext로 응답 할거다.

JSON이 필요하니깐 headers안에다가 넣어준다. 그리고 string형태로 바꿔 준다.

이제 URLPOST request를 보내준다. 그리고 몇개의 데이터를 받아보도록 한다.

브라우저를 새로고침을 해본다. 하지만 에러가 난다.code가 이미 만료가 되었기 때문이다.

code의 유료기간은 10분 밖에 안된다.

fetch가 동작하지 않는건 브라우저에서만 사용 가능하다.

inspect를 해보면 fetch를 사용 할수 있다. 그러면 작동해야 하는데

문제는 fetch기능이 NodeJS에는 포함되어 있지 않다는 거다.

현재 자바스크립트를 쓰고 있어도 function이 똑같지는 않다.

그 둘은 같지 않다. 어떤건 브라우저에서 안되고 어떤 건 NodeJS에서 안된다.

예를 들어서 프론트엔드에서 alert를 사용해 보면 정상적으로 작동한다.

NodeJS에서도 alert가 작동을 하는가 보면 에러가 발생한다.

왜냐하면 alert는 정의되지 않은 함수이다. 이건 다음 파트에서 손 보기로 한다.

그리고 await를 쓰고 싶다면 꼭 async를 써야한다.

async를 쓰지 않으면 await는 작동 하지 않게 된다.

asyncawait는 항상 같이 붙어 다닌다는걸 기억한다.

다음 파트에서 백엔드에서 어떻게 fetch를 쓰는지 알아본다.

왜냐하면 fetch는 굉장히 도움이 많이 된다.

백엔드에서 alert는 할 필요 없더라도 fetch를 쓸일은 있다.

profile
꿈꾸는 개발자

0개의 댓글