<aside> ❔ 참고 페이지

https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps

</aside>

github 로그인 세팅

settings → developer settings → OAuth Apps에서 만들면됨

유저에게 github 로그인 정보 요청

<aside> ❕ github 로그인 기능을 쓰기 위해선 유저가 자신의 정보를 서버로 보내줘야 한다.

그리고 정보를 받는 것을 유저에게 물어보는 페이지로 리다이렉트한다.

</aside>

요청하려면 아래 URL로 redirect

이 때 파라미터를 함께 전달

const baseUrl = "<https://github.com/login/oauth/authorize>";
const configs = {
  client_id: process.env.GTIHUB_CLIENT_ID,
  allow_signup: "false",
  scope: "read:user user:email",
};
const params = new URLSearchParams(configs);
const url = `${baseUrl}?${params}`;

유저가 허가하면 callback 주소(세팅 페이지에서 지정했음)로 리다이렉트 시켜줌.

이 때 이후 사용할 토큰 값으로 code를 query에 포함시켜준다.

github에 access token 요청

받은 code를 가지고 github API에 접근하기 위해 access token을 요청해야 한다.

  1. 아래 URL로 code와 함께 POST 요청을 보낸다.
  2. 리턴 값으로 access_token이 포함되어 있음.
const baseUrl = "<https://github.com/login/oauth/access_token>";
const configs = {
  client_id: process.env.GTIHUB_CLIENT_ID,
  client_secret: process.env.GITHUB_SECRET,
  code: req.query.code,
};
const params = new URLSearchParams(configs).toString();
const url = `${baseUrl}?${params}`;
const data = await fetch(url, {
  method: "POST",
  headers: {
    Accept: "application/json",
  },
});
const json = await data.json();

리턴값 (json)

{
  access_token: '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',
  token_type: 'bearer',
  scope: 'read:user,user:email'
}

github API를 통해 user 정보 접근

access_token으로 github API를 통해 user정보를 요청한다.

이 때 원하는 정보를 얻을 수 있는 url로 요청 각각을 요청하면 된다.

Users - GitHub Docs

여러 로그인 방식에 대한 예외 처리

github 로그인이 아닌 다른 방식들로 로그인 했던 유저의 경우 같은 이메일을 사용할 때 별도의 예외 처리를 해주어야 한다.

github API로 받은 이메일 정보에서 verified, primary가 true인 이메일을 볼 수 있는데 이는 해당 이메일이 인증이 완료되었다는 의미이다. 즉 해당 이메일의 소유가 현재 유저라는 것이 확인되었다는 뜻이다.

그래서 이미 다른 방식으로 가입된 이메일을 사용할 경우 verified, primary 값을 확인 후 로그인을 허용한다.

const verifiedEmailObj = emailDataList.find(
  (emailData) => emailData.primary === true && emailData.verified === true
);
if (!verifiedEmailObj) {
  return res.redirect("/login");
}
const existingUser = await User.findOne({ email: verifiedEmailObj.email });
if (existingUser) {
	...
} else {
	// make new account data
}
return res.redirect('/');