Skip to content

Whale Extension에서 OAuth 적용하기

Donghyun Kim edited this page Dec 16, 2020 · 2 revisions

✔️ 목표

→ Whale Extension 환경에서 OAuth (네이버 소셜 로그인) 적용하기

🔍 문제 인식

  1. Extension 환경에서는 url이 없으므로 일반적인 웹 OAuth 방식을 사용할 수 없다 🙄
  2. 그렇게 방법을 찾아보던 중, Chrome에서 제공해주는 identity 라는 API를 사용하면 OAuth2 access tokens를 얻을 수 있다는 사실을 알게 되었다 😀
  3. 하지만 Whale 환경에서는 많고 많은 API 중, identity만 지원을 하지 않는다......... 😧
    Untitled (5)
  4. 그러면 Chrome identity api를 직접 구현해 보는 건 어떨까?

⚙️ 전체적인 흐름 이해하기

  1. 로그인 버튼을 클릭하면 background.js 파일에 'login' 이라는 message를 전송
  2. message를 받은 background.js는 유저 정보를 담아 sendResponse를 통해 반환 Untitled (6) Untitled (7)

📌 OAuth를 적용하는 과정

  1. 로그인 버튼을 클릭하면 background.js 파일에 'login' 이라는 message를 전송

  2. 네이버 API에 code와 redirect url이 담긴 새로운 팝업 창 생성 (2, 3번 과정)
    Untitled (8)

chrome.windows.create(
      {
        url:
          'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}',
        type: 'popup',
      },
      () => {
        chrome.tabs.onUpdated.addListener(chromeEvnet);
      }
    );
  1. chrome.tabs.onUpdated 함수를 통해 변경된 탭 감지 이벤트 등록

https://nid.naver.com/oauth2.0 url 에 요청을 보내면 code값이 포함된 redirect url으로 팝업 창이 바뀌는 과정에서, tabs.onUpdated 함수가 변경을 감지

  1. redirect url에서 code값 추출 후, server에 code값 전송 (4번 과정)
const chromeEvnet = (tabId, changeInfo, tab) => {
    const redirect_url = changeInfo.url;
    if (redirect_url && redirect_url.includes('code=')) {
      chrome.tabs.remove(tabId, () => {});
      const code = redirect_url.split('code=')[SECOND_ELEM_INDEX].split('&')[FIRST_ELEM_INDEX];
      const body = { code: code };
      fetch('https://www.formulachef.tk/api/auth/login', {
        method: 'POST',
        body: JSON.stringify(body),
        headers: {
          'Content-Type': 'application/json',
        },
      })
       .then((res) => res.json())
        .then((data) => {
          sendResponse(data);
          chrome.tabs.onUpdated.removeListener(chromeEvnet);
        });
}
  1. server에서는 code값을 통해 access token을 반환받음 (5,6,7,8번 과정)

  2. 유저 정보를 DB에 저장 후, client에 유저 정보를 반환해줌 (9번 과정)

  3. sendResponse를 통해 content scriptdata를 넘겨줌 (10번 과정)

sendResponse(data);
  1. tabs.onUpdated.removeListener 함수를 통해 이전에 만들었던 팝업 창 삭제
chrome.tabs.onUpdated.removeListener(chromeEvnet);

📺 전체 코드

// useSaveButtons
chrome.runtime.sendMessage({ message: 'login' }, (response) => {
      if (response.error) {
        setLoginMessage(LoginMessage.LOGIN_FAUILRE);
      }

      if (response.results) {
        const { userToken, userId } = response.results;
        setToken(userToken);
        dispatch(userLogin(userId));
        dispatch(getFavoritesThunk(userId));
        setLoginMessage(LoginMessage.LOGIN_SUCCESS);
      }
}
// background.js

const FIRST_ELEM_INDEX = 0;
const SECOND_ELEM_INDEX = 1;

whale.runtime.onMessage.addListener((message, sender, sendResponse) => {
  const chromeEvnet = (tabId, changeInfo, tab) => {
    const redirect_url = changeInfo.url;
    if (redirect_url && redirect_url.includes('code=')) {
      chrome.tabs.remove(tabId, () => {});
      const code = redirect_url.split('code=')[SECOND_ELEM_INDEX].split('&')[FIRST_ELEM_INDEX];
      const body = { code: code };
      fetch('https://www.formulachef.tk/api/auth/login', {
        method: 'POST',
        body: JSON.stringify(body),
        headers: {
          'Content-Type': 'application/json',
        },
      })
        .then((res) => res.json())
        .then((data) => {
          sendResponse(data);
          chrome.tabs.onUpdated.removeListener(chromeEvnet);
        });
    }
  };
  if (message.message === 'login') {
    chrome.windows.create(
      {
        url:
          'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&state=${state}',
        type: 'popup',
      },
      () => {
        chrome.tabs.onUpdated.addListener(chromeEvnet);
      }
    );
  }
  return true;
});

💒 Home

Home

📆 Planning

📋 요구 사항

📑 프로젝트 설계

📓 Api 명세서

📖 제품 백로그

📺 화면 기획서

📽️ Project

📖 도움말

📷 실행 화면

⚒️ 기술 스택

⚙️ 기술 특장점

✔️ Team Rule

그라운드 룰

☑️ 깃허브 사용 규칙

코딩 컨벤션 규칙

📝 Progress

🌿 1주차 Progress
☘️ 2주차 Progress
🍀 3주차 Progress
🍁 4주차 Progress
🌲 5주차 Progress

📚 학습 정리 공유

🛠️ 기술 관련 공유

Clone this wiki locally