React Native에서 JWT 토큰 디코딩 문제 해결하기

oversleep·2025년 3월 5일
0

troubleshooting

목록 보기
16/19

배경

React Native 애플리케이션을 개발하다 보면 JWT(JSON Web Token)를 사용하여 사용자 인증을 구현하는 경우가 많습니다. 이 과정에서 토큰을 디코딩하여 사용자 ID나 권한 같은 정보를 추출해야 할 때가 있는데, 이때 몇 가지 문제가 발생할 수 있습니다.

특히 웹 환경에서는 문제없이 작동하던 JWT 라이브러리가 React Native 환경에서는 오류를 발생시키는 경우가 종종 있습니다. 이번 포스팅에서는 React Native에서 JWT 토큰 디코딩 중 발생하는 문제와 그 해결 방법에 대해 알아보겠습니다.

문제 상황

React Native 프로젝트에서 로그인 후 JWT 토큰을 디코딩하려고 할 때 다음과 같은 오류가 발생했습니다:

Error decoding token: [InvalidTokenError: Invalid token specified: invalid base64 for part #2 (Can't find variable: atob)]

이 오류는 jwt-decode 라이브러리가 브라우저 환경의 atob 함수에 의존하고 있는데, React Native 환경에서는 이 함수가 기본적으로 제공되지 않아 발생하는 문제입니다.

원인 분석

문제의 원인을 살펴보면:

  1. 환경 차이: 브라우저에서는 atobbtoa 함수가 Base64 인코딩/디코딩을 위해 내장되어 있지만, React Native는 이를 제공하지 않습니다.

  2. 라이브러리 의존성: jwt-decode와 같은 많은 JWT 관련 라이브러리들이 웹 환경을 전제로 개발되어 있어, 브라우저 API에 의존합니다.

해결 방법

1. Base64 디코딩 직접 구현하기

JWT 토큰 디코딩 함수를 직접 구현하는 방법입니다:

import { DecodedToken } from "./types";
import Base64 from "react-native-base64";

export const decodeToken = (token: string): DecodedToken | null => {
  try {
    if (!token || token.split(".").length !== 3) {
      console.error("Invalid token format");
      return null;
    }

    const base64Payload = token.split(".")[1];
    const normalizedPayload = base64Payload
      .replace(/-/g, "+")
      .replace(/_/g, "/");

    const decodedPayload = Base64.decode(normalizedPayload);
    
    return JSON.parse(decodedPayload);
  } catch (error) {
    console.error("Error decoding token:", error);
    return null;
  }
};

이 방법의 장점은 외부 라이브러리 의존성을 줄이고, React Native 환경에 최적화된 방식으로 디코딩을 처리할 수 있다는 것입니다.

2. Polyfill 사용하기

atob 함수를 React Native 환경에 추가하는 방법입니다:

import { DecodedToken } from "./types";
import { jwtDecode } from "jwt-decode";
import { decode as base64Decode } from 'base-64';

// atob polyfill
global.atob = base64Decode;

export const decodeToken = (token: string): DecodedToken | null => {
  try {
    if (!token) {
      return null;
    }
    return jwtDecode<DecodedToken>(token);
  } catch (error) {
    console.error("Error decoding token:", error);
    return null;
  }
};

이 방법을 사용하려면 base-64 패키지를 설치해야 합니다:

npm install base-64
# 또는
yarn add base-64

3. React Native 전용 JWT 라이브러리 사용하기

React Native 환경을 위해 특별히 설계된 JWT 라이브러리를 사용하는 것도 좋은 방법입니다. 예를 들어, react-native-jwt-decode와 같은 라이브러리가 있습니다.

오류 처리 개선

어떤 방법을 선택하든, 오류 처리를 강화하여 앱의 안정성을 높이는 것이 중요합니다:

export const decodeToken = (token: string): DecodedToken | null => {
  try {
    if (!token) {
      console.error("Token is null or undefined");
      return null;
    }
    
    // 디코딩 로직...
    
  } catch (error) {
    // 자세한 오류 로깅
    console.error("Error decoding token:", error);
    
    // 앱이 중단되지 않도록 null 반환
    return null;
  }
};

추가 고려사항

1. 토큰 디코딩이 실패할 경우의 대응

토큰 디코딩이 실패하더라도 앱의 주요 기능은 계속 작동할 수 있도록 해야 합니다. 다음은 이를 처리하는 방법의 예시입니다:

const handleLoginEvent = async (data: LoginEventData) => {
  try {
    const { accessToken, refreshToken, jti, navigation, shouldNavigate = true } = data;

    // 토큰 디코딩 시도
    let userId = "";
    try {
      const decodedToken = decodeToken(accessToken);
      userId = decodedToken?.userId?.toString() ?? "";
    } catch (decodeError) {
      console.error("Token decoding failed, continuing without userId:", decodeError);
      // 디코딩 실패해도 계속 진행
    }

    // AsyncStorage에 데이터 저장
    await AsyncStorage.multiSet([
      ["jti", jti],
      ["accessToken", accessToken],
      ["refreshToken", refreshToken],
      ["isLoggedIn", "true"],
      ["userId", userId],
    ]);

    // 네비게이션 처리
    if (shouldNavigate && navigation) {
      navigation.reset({
        index: 0,
        routes: [{ name: "MainTab" }],
      });
    }
  } catch (error) {
    console.error("로그인 처리 실패:", error);
  }
};

2. 백엔드 응답 활용

가능하다면, 토큰 디코딩에 의존하지 않고 API 응답에서 직접 사용자 ID 등의 정보를 받아오는 것도 좋은 방법입니다:

// 로그인 API 응답
interface LoginResponse {
  accessToken: string;
  refreshToken: string;
  jti: string;
  userId: number; // 백엔드에서 추가로 제공
}

결론

React Native 환경에서 JWT 토큰 디코딩은 웹 환경과 다른 접근 방식이 필요합니다. 직접 구현, polyfill 사용, 또는 전용 라이브러리 사용 등 상황에 맞는 최적의 방법을 선택하면 됩니다.

중요한 점은 토큰 디코딩 실패가 앱의 전체 기능에 영향을 미치지 않도록 견고한 오류 처리를 구현하는 것입니다. 이를 통해 사용자는 원활한 앱 경험을 유지할 수 있습니다.

참고 자료

profile
궁금한 것, 했던 것, 시행착오 그리고 기억하고 싶은 것들을 기록합니다.

0개의 댓글