🔥 결과
이렇게 Github로 로그인 버튼을 누르면 인증 과정을 거쳐 사용자의 정보를 가져올 수 있다.
전체 코드는 하단 Github Repository 링크를 첨부했다.
🌠 환경
"dependencies": {
"axios": "^0.27.2",
"cookie-parser": "~1.4.4",
"dotenv": "^16.0.3",
"express": "~4.16.1",
"pug": "2.0.0-beta11"
}
Express로 서버 포트를 열고 클라이언트 단에서 axios로 통신하는 매우 간단한 환경이다.
🔹 서버 파일
- app.js
- nodemon으로 가장 먼저 실행되는 파일로, express 미들웨어 설정과 router 호출을 담당
- routers/index.js
- 메인 페이지를 라우팅
- routers/oauth.js
- github oauth 관련 페이지를 라우팅
- utils.js
- github oauth 관련 유틸 함수들 모음
- constants.js
- 상수 관리 파일
🔹 클라이언트 파일
- views/index.pug
- routers/index.js에 의해 랜더링 되는 메인 페이지
- public/javascripts/index.js
- public/stylesheets/style.css
🌊 흐름
✅ 1. 로그인 이벤트 발동
// index.js
$loginBtn.addEventListener("click", () => {
location.href = "/github-oauth";
});
Github로 로그인 버튼을 누르면 페이지 이동이 일어난다.
✅ 2. Github OAuth 페이지에 요청
// app.js
app.use("/github-oauth", oauthRouter);
페이지 이동을 Express 라우터가 잡는다.
Github OAuth 명세에 나와있듯이,
위 링크를 url로, Required 마킹이 되어있는 client_id 를 param으로 설정해서 요청했다.
// routers/oauth.js
router.get("/", function (req, res, next) {
const url = URL.github_authorization;
const client_id = GITHUB_DATA.client_id;
const param = new URLSearchParams({ client_id }).toString();
res.redirect(`${url}?${param}`);
next();
});
...
✅ 3. 인증 -> Authorization Code
위 화면은 Github로 로그인 버튼을 누르면 나오는 페이지이다.
사용자가 Authorize 버튼을 누르면 url query에 담긴 Authorization Code 발급과 함께 Callback이 일어난다.
// routers/oauth.js
router.get("/callback?*", async function ({ query: { code } }, res, next) {
const accessToken = await getAccessTokenByAuthorizationCode(code);
const { name, public_repos } = await getUserDataByAccessToken(accessToken);
const userData = { userName: name, userRepo: public_repos };
res.cookie("userData", userData);
res.redirect("/");
next();
});
위 코드는 Callback 요청을 라우터가 잡아서 실행되는 코드이다.
이어지는 설명은 utils.js에서 import 하여 사용한 2개의 메서드가
어떻게 Authorization Code를 사용자 정보로 바꾸는지에 대한 과정이다.
✅ 4. Authorizaion Code -> Access Token
//utils.js
async function getAccessTokenByAuthorizationCode(code) {
return await axios({
method: METHOD.post,
url: URL.github_access_token,
headers: {
accept: "application/json",
},
data: {
client_id: GITHUB_DATA.client_id,
client_secret: GITHUB_DATA.client_secret,
code: code,
},
}).then((res) => res.data.access_token);
}
url query에서 뽑아낸 Authorization Code를 인자로 받아서 Access Token을 요청한다.
맨 처음 Authorization 요청을 할 때와 마찬가지로, 위 주소를 url로 하고
Required 마킹된 client_id, client_secret, code 만 data로 설정하여 POST 요청을 보냈다.
✅ 5. Access Token -> userData
// utils.js
async function getUserDataByAccessToken(accessToken) {
return await axios({
method: METHOD.get,
url: URL.github_user_api,
headers: {
Authorization: `token ${accessToken}`,
},
}).then((dataObject) => dataObject.data);
}
마찬가지로 위 주소를 url로 하여 headers에 Access Token을 담아서 요청을 보냈다.
✅ 6. 사용자 정보 추출
// routers/oauth.js
router.get("/callback?*", async function ({ query: { code } }, res, next) {
const accessToken = await getAccessTokenByAuthorizationCode(code);
const { name, public_repos } = await getUserDataByAccessToken(accessToken);
const userData = { userName: name, userRepo: public_repos };
res.cookie("userData", userData);
res.redirect("/");
next();
});
다시 3번 과정의 callback 이후 실행되는 코드이다.
사용자의 Github 정보(userData)가 응답으로 반환되면 위 코드처럼 원하는 정보만 가져와 사용할 수 있다.
name, public_repo 말고도 email, followers, 다양한 url들을 가져올 수 있다.
일단 사용자 정보를 메인 페이지에서 랜더링 하기 위해 cookie에 담았다.
✅ 7. 사용자 정보 랜더링
// routers/index.js
router.get("/", function (req, res, next) {
let dataObject = {};
// Github OAuth 로 받아온 유효한 사용자의 정보가 있다면 화면에 표시
const isUserDataExist = req.cookies.userData !== undefined;
if (isUserDataExist) {
const { userName, userRepo } = req.cookies.userData;
dataObject = { userName, userRepo };
}
res.render("index", { ...dataObject });
next();
});
메인 페이지는 cookie를 보며 userData가 있다면 화면에 표시하도록 한다.
Github Repository 링크
https://github.com/edac99/github-oauth-nodejs
edac99/github-oauth-nodejs
Github OAuth with NodeJS and Express.js. Contribute to edac99/github-oauth-nodejs development by creating an account on GitHub.
github.com
'기억 저장소' 카테고리의 다른 글
[nCloud] 서버와 DB 따로 배포 후 연동 (2) | 2022.10.14 |
---|---|
[TypeORM] Cannot add or update a child row: a foreign key constraint fails 오류 해결 (0) | 2022.10.09 |
TypeScript + Express 초간단 세팅 (0) | 2022.10.05 |
JS로 JWT 로그인 구현 (Passport.js 미사용) (0) | 2022.10.02 |
nCloud 서버 배포 에러 해결 모음집 (0) | 2022.09.24 |
댓글