1. Github Login
- 이어서 하면 github에서 authorized버튼을 누른 이후 callback url로 연결되었음
OAuth 앱 권한 부여 - GitHub Docs
다른 사용자가 OAuth app에 권한을 부여하도록 설정할 수 있습니다.
docs.github.com
- 공식문서의 웹 애플리케이션 흐름 2번에 따르면 github에서 받은 토큰을 access 토큰으로 바꿔줘야함
- client_id는 또 사용되기에 .env에 넣을거임
- 어차피 parameter에 나오기 때문에 보안과 아무 관련없고 전역에서 쓰기 위함임
- client_secret은 말 그대로 비밀인데 오로지 백엔드에만 존재해야되는 secret임
- Wetube 앱에서 생성하여 .env에 추가
- code는 callback url에 나와있는 것을 사용
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 request만 보낼 거임
- 다른 강좌에서 fetch를 쓴 적이 있음
- 무언가를 하고 싶거나, 무언가를 가져오고 싶을 때 사용했음
2. Fetch
- 잠깐 기억을 되새겨보면, fetch("url")을 사용하여 다른 서버를 통해 데이터를 가져올 수 있었음
- 하지만 res.body에 담겨있는 날 것의 url 로는 제대로 된 객체를 가져올 수 없음
- 그렇기에 중간에 .json 함수가 response의 stream을 가져와 다 읽어보고, res.body의 텍스트를 promise의 형태로 반환함
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}`;
// finalUrl에 POST 요청을 보내 데이터를 받아 오고
const data = await fetch(finalUrl, {
method: "POST",
headers: {
Accept: "application/json",
},
});
// 그 데이터에서 json을 추출
const json = await data.json();
res.send(JSON.stringify(json));
};
- 처음 fetch를 배울 땐 .then을 사용했지만 둘다 사용가능하고 본인이 선호하는 방식으로 코드 작성
- 이후에 이것보다도 간결한 방법이 있음
- 현재 node.js를 최신 버전으로 사용하고 있다보니 node-fetch가 node-modules안에 있음
- fetch는 원래 브라우저에서만 사용가능했음
- 예로 alert는 프론트엔드에서 사용가능했지만, node.js에서는 안됨
- 그래도 혹시 낮은 버전에서 사용할 수 있다는걸 알아야 함
- https://www.npmjs.com/package/node-fetch
node-fetch
A light-weight module that brings Fetch API to node.js. Latest version: 3.3.2, last published: a year ago. Start using node-fetch in your project by running `npm i node-fetch`. There are 39134 other projects in the npm registry using node-fetch.
www.npmjs.com
3. API 접근
- 이제 github로 로그인을 시도해보면 res.send를 했기 때문에 홈페이지에 access_token이 출력됨
- access_token을 가지고 API에 접근해야 함
// 그 데이터에서 json을 추출
const json = await data.json();
// json에 access_token이 있으면
if ("access_token" in json) {
// API에 접근
} else {
// 아니면 login으로 돌려보냄
return res.redirect("/login");
}
- 이렇게 할 수도 있고, res.render를 할 수도 있음
- 유저에게 alert같은 notification을 보여주고 싶은데, 이건 나중에 해볼 예정
- 강사는 이 상황에 template을 render하기 싫다고 했음
- 그렇게 되면 유저가 url에서 template을 보게 되며, 유저가 여기서 template을 보면 안됨
- 해당 controller 밖에서 어떤 것도 render하고 싶지 않다고 함
- notification을 구현하게 되면 모두 해결될 문제
- notification은 유저가 /login으로 redirect하게 하고, /login에서 에러 메시지를 볼 수 있게 할 수 있음
- 일단 현재까지 순서가 굉장히 이해하기 어려우므로 정리
- github로 로그인을 시도하면, router를 통해 /github/start로 이동해 startGithubLogin 함수로 이동하여 Wetube 앱에 있는 client_id, scope를 공식문서에 나와있는 url로 전송
- 그러면 github에서는 callback url에 등록된 url로 돌려보내는데, router를 통해 /github/finish로 이동 finishGithubLogin 함수로 이동하는데 github에서 url에 임시 code를 붙여서 옴
- 이 code를 access token으로 교환해야 되는데, 공식문서에서 필수로 요구하는 client_id, client_secret, code를 fetch를 사용하여 POST request를 보내면 json타입으로 된 access_token으로 줌
- access token을 사용하여 API에 접근하면 유저 정보 object를 넘겨줌
- 하지만 object를 잘 살펴보면 email: null이라고 나옴
- 내 email이 없거나 private이라는 뜻
- email이 null일 때를 대비하여 또다른 request를 만들어야 함
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}`;
// finalUrl에 POST 요청을 보내 데이터를 받아 오고
const tokenRequest = await (
await fetch(finalUrl, {
method: "POST",
headers: {
Accept: "application/json",
},
})
).json();
// json에 access_token이 있으면
if ("access_token" in tokenRequest) {
// API에 접근
const { access_token } = tokenRequest;
const userRequest = await (
await fetch("https://api.github.com/user", {
headers: {
Authorization: `token ${access_token}`,
},
})
).json();
console.log(userRequest);
} else {
// 아니면 login으로 돌려보냄
return res.redirect("/login");
}
};
- 이후 작업은 다음 글에서 마무리
'개발 > Node.js' 카테고리의 다른 글
Github Login Recap again again (0) | 2024.11.13 |
---|---|
Github Login / Logout (0) | 2024.11.13 |
Dotenv / Github Login / UrlSearchParams (0) | 2024.11.12 |
Secret Domain Expiration Etc (0) | 2024.11.12 |
MongoStore resave saveUninitialized (0) | 2024.11.12 |