Spotify 소셜 로그인 하기 - 1편

이은지·2022년 7월 24일
5
post-thumbnail

학회 플젝에서 진행했었던 프로젝트 내의 Spotify 소셜 로그인 기능에 대해 작성해보려고 합니당~.~
당시 플젝 기간이 일주일도 채 안됐었어서 대강 굴러가는 대로 코드를 짰었는데, 현재 리팩토링 작업을 하고 있어 기록 겸 쓰는 글입니다.

저희는 백엔드와 프론트엔드가 함께 로그인 기능을 구현했는데, NextJS 쓰는 분이라면 그냥 Next-Auth를 쓰십시오... 그때 10분만에 만들 수 있었어요

✅ 구현 목표

앱 내에 만든 스포티파이 플레이어에서 노래를 재생하기 위해서는, 우리 어플리케이션에 로그인할 때 스포티파이 프리미엄 계정으로 소셜 로그인을 해야 한다! 소셜 로그인을 하면 access_token을 주는데, 이 토큰을 Spotify Web API의 인자로 넣어야 노래 재생이 가능하기 때문.

또 유의해야 할 점은 토큰의 유효 시간이다. 1시간이 지나면 토큰이 expired 상태가 되어 노래 재생이 불가능해진다. 이때 다시 새로운 토큰을 요청해야 한다.

🎧 Spotify 소셜 로그인 과정 이해

아래 이미지는 공식문서에 나와 있는 authorization code flow다.
백엔드 프론트엔드 둘 다 이 과정을 제대로 이해 못해서 한참 헤맸다 ㅋㅋ 😞

https://developer.spotify.com/documentation/general/guides/authorization/code-flow/

위 이미지의에서
APPLICATION = 우리가 지금 만들고 있는 앱을 의미한다
USER = 우리 앱에 로그인하려는 유저를 의미한다.

보면 access_token을 얻기 위해서 두 번의 요청이 필요하다.
❶번에서 유저가 로그인을 하면 바로 토큰을 주는 게 아니라 토큰을 얻을 수 있는 code를 리턴한다. 이 code를 가지고 스포티파이 측에 한 번 더 요청을 해야(❷번) 응답으로 토큰을 받을 수 있다.

토큰은 참고로 이렇게 생겼다.
BQCEB5lEagZLI5J9ims5z_aVbOGLYY5S_zSysgLqiUQtfiSAE8QO8doBwS55oL69RJK3qaN89hClJzInfEPVAnd9I0SyVOmy7Y0XomvHu8QE3DML8ic_o7sOUuY0TyLApQ7MEi--X_0eT0NSQlYvGOea3gwww-bh-KjRFrPEeTrtqSj8oWMGMz6Jq4LWMIdsnV-Z5YqqCe-No8IFKoVk6rqWJioTubOHVfo

🛠 구현하기

우리가 구현한 방식은 다음과 같다.

  1. Front: 유저가 로그인 버튼을 클릭하면 Back에 requestLogin API를 호출한다.
  2. Back: Spotify에 로그인을 요청한다.
  3. Spotify: 유저가 로그인할 수 있는 스포티파이 로그인 페이지 url을 리턴한다.
    Back은 응답으로 받은 이 url을 Front에 전달한다.(requestLogin의 응답으로)
  4. Front: 해당 url로 유저를 이동시킨다.
  5. User: 해당 페이지 내에서 로그인 버튼을 클릭
  6. Spotify: 우리가 미리 등록해둔 Redirect URL로 유저를 리다이렉션 시킨다.
    이때 url의 query string에 access_token을 받을 수 있는 code를 포함해 리다이렉트 한다.
  7. Front: url을 파싱해 code를 얻어낸다. 얻어낸 code를 query string에 담아getToken API를 호출한다.
  8. Back: 프론트가 보내준 코드를 사용해 스포티파이에 acess_token을 요청. 응답으로 받은 access_token을 Front에 전달한다.(getToken의 응답으로)

더럽게 복잡하네요

Redirect URL등록은 여기다 하시면 돼요. 👇

API 호출 함수 작성

백엔드랑 상의해서 작성한 API 명세다. 이 명세에 따라 함수를 작성했다.

TokenContext

토큰을 여러 곳에서 사용하기 때문에 토큰을 저장하는 Context를 생성했다.

// context/TokenContext.tsx

import { createContext, useContext, useEffect, useState } from "react";

const TokenContext = createContext<string | null>(null);
const SetTokenContext = createContext<(token: string | null) => void>(() => {});

export const TokenProvider = ({ children }: { children: React.ReactNode }) => {
  const [token, setToken] = useState<string | null>(null);
  return (
    <TokenContext.Provider value={token}>
      <SetTokenContext.Provider value={setToken}>
        {children}
      </SetTokenContext.Provider>
    </TokenContext.Provider>
  );
};

export const useToken = () => {
  const token = useContext(TokenContext);

  return token;
};

export const useSetToken = () => {
  const setToken = useContext(SetTokenContext);

  return setToken;
};

useToken과 useSetToken Hook을 활용하면 어디서든 토큰에 접근하고 토큰을 수정할 수 있다.

플로우

❶ 유저가 앱에 접속
👉 index.tsx의 useCheckToken이 실행된다.

const useCheckToken = () => {
  const token = useToken();
  const setToken = useSetToken();
  const router = useRouter();

  useEffect(() => {
    if (token) {
      isTokenValid(token).then((isValid) => {
        if (!isValid) {
          setToken(null);
          router.push("/login");
        }
      });
    } else {
      router.push("/login");
    }
  }, [router, setToken, token]);
};

useToken에 토큰 있으면 isTokenValid 로 토큰의 유효성을 검사한다.

  • 유효하지 않다면 로그인 페이지로 리다이렉트
  • 유효하다면 메인 페이지로 이동

useToken에 토큰 없으면 바로 로그인 페이지로 리다이렉트 한다.

❷ login.tsx

로그인 버튼이 있는 페이지. 유저가 버튼을 클릭하면 requestLogin API를 호출한다.

❸ loading.tsx

Spotify App에 등록해놓은 Redirect URL이다.
스포티파이 로그인 페이지에서 유저가 스포티파이로 로그인 하면 해당 페이지로 리다이렉트 된다.

해당 페이지의 useEffect에서 query string을 파싱하고, getToken API를 호출한다.
getToken의 응답으로 받은 access_token을 useSetToken을 활용해 저장한다.


이게 프로젝트 마지막 날까지의 진행 상황이다. 근데 문제가 많아서 혼자 리팩토링 중이다.

우선 가장 큰 문제
새로고침 하면 로그인이 풀린다

다음 포스팅에선 새로고침 시에도 로그인이 유지되는 기능을 구현해 보겠다.

0개의 댓글