본문 바로가기

TIL

TIL - Next.js 클라이언트 컴포넌트에서 API 토큰 관리 문제 트러블 슈팅

문제 상황

무한 스크롤 기능을 구현하면서 클라이언트 컴포넌트에서 Spotify API에 직접 요청을 보내야 했습니다. 그러나 API 토큰이 서버 측에서만 관리되고 있어 클라이언트에서 API 요청을 할 수 없는 문제가 발생했습니다. 특히 빌드 과정에서 다음과 같은 문제가 있었습니다:

  • 로컬 개발 환경에서는 API 라우트 핸들러가 정상적으로 작동했지만,
  • 빌드 시에는 로컬 서버가 실행되지 않아 API 라우트 핸들러에 요청을 보낼 수 없었습니다.

해결 방안

이 문제를 해결하기 위해 spotify.api.ts 파일에 다음과 같은 코드를 추가했습니다:

async getAccessToken() {
  if (typeof window !== 'undefined') {
    const response = await fetch('/api/spotify-token');
    const data = await response.json();
    this.accessToken = data.token;
    this.tokenExpirationTime = Date.now() + 3600 * 1000;
    if (!this.accessToken) {
      throw new Error("Failed to obtain access token");
    }
    return this.accessToken;
  }

  // 서버 사이드 토큰 요청 로직
  const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64');
  const response = await fetch("https://accounts.spotify.com/api/token", {
    method: "POST",
    headers: {
      Authorization: `Basic ${auth}`,
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: "grant_type=client_credentials",
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();
  this.accessToken = data.access_token;
  this.tokenExpirationTime = Date.now() + data.expires_in * 1000;

  if (!this.accessToken) {
    throw new Error("Failed to obtain access token");
  }

  return this.accessToken;
}

작동 원리

  1. 클라이언트 사이드 체크: typeof window !== 'undefined'로 코드가 브라우저에서 실행 중인지 확인합니다.
  2. 클라이언트 사이드 토큰 요청: 브라우저 환경에서는 API 라우트를 통해 토큰을 요청합니다.
  3. 서버 사이드 토큰 요청: 서버 환경에서는 직접 Spotify API에 토큰을 요청합니다.
  4. 빌드 시 동작: 빌드 과정에서 window 객체가 없으므로, 서버 사이드 로직이 실행됩니다. 이로 인해 빌드 오류를 방지할 수 있습니다.

학습 포인트

  1. 환경에 따른 조건부 실행: 클라이언트와 서버 환경에서 각각 다른 로직을 실행하는 방법을 배웠습니다.
  2. API 토큰 관리의 중요성: 보안을 위해 서버에서 관리하되, 클라이언트에서도 필요시 안전하게 접근할 수 있는 방법을 구현했습니다.
  3. 빌드 프로세스 이해: Next.js의 빌드 프로세스와 API 라우트의 동작 방식에 대해 더 깊이 이해하게 되었습니다.
  4. 에러 처리의 중요성: 토큰 획득 실패 시 적절한 에러 처리를 통해 안정성을 높였습니다.

결론

이 경험을 통해 Next.js에서 클라이언트와 서버 로직을 효과적으로 분리하면서도 안전하게 연동하는 방법을 배웠습니다. 특히 무한 스크롤과 같은 클라이언트 사이드 기능 구현 시 API 토큰 관리의 중요성을 깨달았습니다. 이러한 패턴은 보안을 유지하면서도 필요한 기능을 제공하는 우수한 아키텍처라고 생각합니다. 앞으로 다른 API 통합 작업에서도 이 접근 방식을 활용할 수 있을 것 같습니다.