소셜 로그인과 로그아웃

345·2023년 4월 15일
0

🪪 OAuth 2.0

서비스에 직접 회원가입하지 않고도 기능을 사용할 수 있게 해주는, "구글로 로그인하기" 혹은 "페이스북으로 로그인하기" 등의 기능이 존재합니다.

어떠한 애플리케이션에서 "구글로 로그인하기" 를 한다고 합시다.
그럼 이 애플리케이션은 구글에 저장된 사용자 정보에 접근할 수 있어야 합니다.
이렇듯 애플리케이션이 타사 서비스에서 정보 접근 권한을 얻도록 하는 표준 프로토콜을 OAuth 라고 합니다.

즉, 사용자가 내 서비스에서 회원가입하는 과정을 거치지 않고도 타 서비스를 활용해서
인증과 인가 절차를 처리하도록 하는 것이죠.

  • 인증: 사용자 신원 확인 (아이디와 비밀번호 등...)
  • 인가: 정보 접근 권한 획득 (사용자 이름 등의 정보 얻기)

✨ OAuth 과정

OAuth 2.0 Protocol Flow

공식문서에서 설명하는 프로토콜 구조 이미지입니다.
다음과 같은 과정을 거칩니다.


  1. 클라이언트가 resource owner (ex. 구글)에게 권한 요청
  2. resource owner 가 요청 승인
  3. 클라이언트가 승인된 권한으로 authorization server 에서 access token 을 받음
  4. 클라이언트는 access token 으로 resource server 에서 정보 접근

권한을 얻어와 토큰을 받고, 토큰을 이용하여 사용자 정보에 접근합니다.


🔥 OAuth 적용

실제 타사 서비스를 이용하여 OAuth 를 적용한 로그인을 구현해봅시다.
대부분 다음과 같은 과정을 거칩니다.


  • 사전 세팅
  1. 어플리케이션 등록

    타사 서비스를 사용할 OAuth App 으로 자사 서비스 등록

  2. Client ID, Client Secret 받기

    등록한 OAuth App 에 부여되는 값. Client ID 는 공개해도 괜찮지만 Client Secret 은 비밀로 유지해야 함❗

  3. Authorization Callback 을 위한 Redirect URL 입력

    인가 코드가 Redirect URL 로 전달됨


  • 구현
  1. API 로 인가 코드 요청
  2. Redirect URL 로 인가 코드 전달 받기
  3. 받아온 인가 코드로 토큰 발급 요청
  4. 발급받은 토큰으로 타사 서비스의 사용자 정보 조회


깃허브 로그인

Authorizing OAuth Apps - GitHub Docs

위 링크 참고해서, OAuth App 에 권한을 받아옵시다.
권한을 받는 웹앱 플로우는 다음과 같습니다.

Users are redirected to request their GitHub identity
Users are redirected back to your site by GitHub
Your app accesses the API with the user's access token

  1. 처음에 GitHub 사용자 인증을 위한 링크로 이동
    (깃허브 로그인)
  2. 다시 원래 사이트로 리다이렉트
  3. 앱은 액세스 토큰을 받아서 API 사용

세팅

OAuth App 에 나의 서비스를 등록해줍시다.
깃허브 세팅OAuth Apps 에서 새로운 OAuth App 을 생성합니다.

Homepage URLAuthorization callback URL 을 지정해줍니다.
Homepage URL 은 어플리케이션의 URL,
Authorization callback URL 에는 app 이 권한을 얻은 후 이동할 URL 을 입력합니다.

여기서 Client ID 와 Client Secret 값을 얻을 수 있습니다.
.env 에 저장해둡니다.


이제 OAuth app 을 만들었으면 아래 공시문서를 따라하여
OAuth 앱(나의 앱)에 권한을 부여하도록 할 수 있습니다.

Authorizing OAuth apps

과정은 다음과 같습니다.

  1. 사용자의 깃허브 아이덴티티를 받아오기 위해 아래 링크로 GET 요청하기
GET https://github.com/login/oauth/authorize

이때, 파라미터로 client_id 를 넘겨줘야 합니다.
OAuth app 을 만들 때 Client ID 값도 같이 생성됐었죠? 그 값을 입력해주면 됩니다.
공식문서를 보면 다양한 파라미터가 존재하고 그 값에 따른 옵션이 설명되어 있습니다.

이 중 scope 파라미터로 얻어올 토큰의 권한을 제어할 수 있습니다.
사용자의 정보를 어디까지 열람해서 사용할지 결정한다고 보면 됩니다.
scope 로 넘겨준 값에 따라 접근 가능한 정보의 범위가 결정됩니다.

scope 권한

scope 권한은 위 링크에서 살펴봅시다...

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);

위처럼 https://github.com/login/oauth/authorizeconfig 처럼 파라미터 설정을 해서 최종 URL 을 만들어주고 거기로 GET 요청을 해주면 됩니다.


  1. code 파라미터와 access token 교환하기

1번에서 GET 요청을 해주면 설정해둔 Authorization callback URLcode 파라미터와 함께 리다이렉트 됩니다.

이제 이 code 를 가지고 Client ID 와 Client Secret 을 입력하여
아래 URL 로 POST 요청을 해주면 access token 을 얻을 수 있습니다.

POST https://github.com/login/oauth/access_token

code 의 유효기간은 10분이니 그 안에 토큰과 교환해줘야 합니다.

  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 tokenRequest = await (
    await fetch(finalUrl, {
      method: "POST",
      headers: {
        Accept: "application/json",
      },
    })
  ).json();

URLSearchParamsconfig 의 파라미터를 설정한 최종 URL 을 만듭니다.
그 후 fetch 로 해당 URL 에 POST 요청을 해줍니다.
헤더에 Accept: application/json 을 추가해주면 해당 형식으로 응답받을 수 있습니다.

응답은 tokenRequest 로 받으며, 토큰은 access_token 이라는 이름으로 받아옵니다.


  1. 토큰을 사용해서 API 이용하기

2번에서 토큰을 얻어왔으니, API 를 이용하여 정보를 얻어올 수 있습니다.
헤더에 Authorization: Bearer OAUTH-TOKEN 을 포함해주고 API URL 에 GET 요청을 해줍니다.

Authorization: Bearer OAUTH-TOKEN
GET https://api.github.com/user

위처럼 유저 정보를 얻어올 수 있습니다.

  const { access_token } = tokenRequest;
  const apiUrl = "https://api.github.com";

  const userData = await (
    await fetch(`${apiUrl}/user`, {
      headers: {
        Authorization: `Bearer ${access_token}`,
      },
    })
  ).json();

이렇게 얻어온 유저 정보로 DB 와 대조하여 로그인하거나, 새로운 유저를 생성하거나 할 수 있습니다.


로그아웃

로그아웃을 위해서는 세션에 기록된 유저 정보를 삭제해줘야겠죠.

req.session.destroy();

위 코드를 사용하면 세션 정보를 삭제할 수 있습니다.

profile
기록용 블로그 + 오류가 있을 수 있습니다🔥

0개의 댓글