github로 로그인하기

markus·2021년 7월 11일
0

Youtube Clone

목록 보기
8/16

지난 시간에는 local에서 로그인을 구현했다. 이번에는 github로 구현해보자.

Authorizing OAuth Apps

흐름

  1. Users are redirected to request their GitHub identity
  2. Users are redirected back to your site by GitHub(get code)
  3. Your app accesses the API with the user's access token

1. Request a user's GitHub identity

export const githubLogin = (req, res) => {
  const base_url = "https://github.com/login/oauth/authorize";
  const config = {
    client_id: process.env.CLIENT_ID,
    allow_signup: false,
    scope: "read:user user:email", // space로 구분한다.
  };
  const config_url = new URLSearchParams(config).toString();
  const final_url = `${base_url}?${config_url}`;
  return res.redirect(final_url);
};

client_id : new OAuth app을 만들면 생기는 client ID
scope : github에게 요청하는 유저 정보 종류들
URLSearchParams : url 관련 object이다. toString()을 사용하면 string을 url로 바꿔준다.

2. Users are redirected back to your site by GitHub

성공적으로 github로부터 응답을 받으면 code를 받게 된다. 이 code는 10분 동안만 유효하며 한 번 사용하면 재사용이 불가능하다.

export const githubCallback = async (req, res) => {
  const base_url = "https://github.com/login/oauth/access_token";
  const config = {
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    code: req.query.code,
  };
  const config_url = new URLSearchParams(config).toString();
  const final_url = `${base_url}?${config_url}`;
  const tokenRequest = await (
    await fetch(final_url, {
      method: "POST",
      headers: {
        Accept: "application/json",
      },
    })
  ).json();
};

fetch를 통해 access_token을 발급받고 있다.

✔ json 형태로 발급받는 경우

    const data = await fetch(final_url, {
      method: "POST",
      headers: {
        Accept: "application/json",
      },
    })
  const json = await data.json();
  console.log(json);

▶ 출력값

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

✔ text 형태로 발급받는 경우

    const data = await fetch(final_url, {
      method: "POST",
      headers: {
        Accept: "text/html",
      },
    })
  const text = await data.text();
  console.log(text);

▶ 출력값

access_token=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&scope=read%3Auser%2Cuser%3Aemail&token_type=bearer

json 형태로 받자.


3. Use the access token to access the API

access_token을 발급받으면 유저의 정보를 열람할 수 있다. 단, scope에서 요청한 정보만 볼 수 있다.

export const githubCallback = async (req, res) => {
  ...
  
  if ("access_token" in tokenRequest) {
    const { access_token } = tokenRequest;
    const apiUrl = "https://api.github.com";
    const userData = await (
      await fetch(`${apiUrl}/user`, {
        headers: {
          Authorization: `token ${access_token}`,
        },
      })
    ).json();
    console.log(userData);
    return res.redirect("/");
  } else {
    return res.redirect("/login");
  }
};

▶ 출력값

{
  ...
  type: 'User',
  site_admin: false,
  name: 'abc',
  company: null,
  blog: '',
  location: null,
  email: 'abc@naver.com',
  hireable: null,
  ...
}

이로써, github로 로그인을 해보았다.

만약에...

유저가 email을 private으로 설정하면 어떻게 될까? email: null이 출력된다. 이런 경우에는 어떻게 해야 할까?

github에서 관리하는 Users를 참고해보자.

export const githubCallback = async (req, res) => {
  ...
  
  if ("access_token" in tokenRequest) {
    ...
    
    const emailData = await (
      await fetch(`${apiUrl}/user/emails`, {
        headers: {
          Authorization: `token ${access_token}`,
        },
      })
    ).json();

    console.log(emailData)
    const email = emailData.find(
      (email) => email.primary === true && email.verified === true
    );
    return res.redirect("/");
  } else {
    return res.redirect("/login");
  }
};

▶ 출력값

[
  {
    email: 'abc@naver.com',
    primary: true,
    verified: true,
    visibility: 'public'
  },
  {
    email: '80094949+abc@users.noreply.github.com',
    primary: false,
    verified: true,
    visibility: null
  }
]

github가 가지고 있는 모든 email이 출력됐다. primary: true, verified: true인 email을 찾으면 된다.

기타

앞서 fetch를 사용할 때 headers를 사용했다. headers에 대해 알아보자.

headers는 브라우저와 서버가 요청 또는 응답할 때, 정보를 전송할 수 있도록 해준다. 여기서 정보의 형태를 결정하는 application/json, text/html 등을 "MIME type"이라고 부른다.

0개의 댓글