# 서비스별 인증 처리 리팩토링 가이드 ## 1) 문서 목적 여러 서비스 앱에서 중복 구현된 인증 로직을 공통 모듈(`@common/auth`) 기반으로 통일하기 위한 표준 가이드 핵심 원칙: - 인증 정책은 공통 모듈에 모은다. - 서비스별 차이는 설정(`authConfig`)으로만 표현한다. - 토큰 갱신 타이머는 JWT `exp` 기준으로 계산한다. ## 2) 공통 아키텍처 인증 관련 책임을 아래처럼 분리한다. - `shared/config/env.ts`: 환경 변수 노출 - `shared/config/auth.ts`: 서비스별 인증 키/도메인 설정 - `entities/auth/lib/token-manager.ts`: 공통 토큰 매니저 생성/re-export - `entities/auth/api/*`: 로그인/토큰 갱신 API 오케스트레이션 - 레이아웃: BaseLayout 컴포넌트에 `tokenManager` 주입 ## 3) 단계별 리팩토링 방법 ### 3-1. 환경 변수 정의 통일 (`shared/config/env.ts`) 서비스마다 이름이 다른 인증 환경 변수를 한 곳에서 노출한다. 예시 코드: ```ts export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; export const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; export const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token"; export const REFRESH_TOKEN = process.env.NEXT_PUBLIC_REFRESH_TOKEN || "refresh-token"; export const COOKIE_DOMAIN = process.env.NEXT_PUBLIC_COOKIE_DOMAIN; ``` ### 3-2. 서비스별 인증 설정 분리 (`shared/config/auth.ts`) 하드코딩된 키명을 제거하고 `AuthConfig`로 매핑한다. 예시 코드: ```ts import type { AuthConfig } from "@common/auth"; import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME, COOKIE_DOMAIN, REFRESH_TOKEN, } from "./env"; export const authConfig: AuthConfig = { authUserId: AUTH_USER_ID, claimName: CLAIM_NAME, cookieDomain: COOKIE_DOMAIN, accessToken: ACCESS_TOKEN, refreshToken: REFRESH_TOKEN, }; ``` ### 3-3. 토큰 매니저 공통화 (`entities/auth/lib/token-manager.ts`) 서비스 고유 `TokenManager` 구현을 제거하고 `createTokenManager`를 사용한다. 예시 코드: ```ts import { authConfig } from "@/shared/config/auth"; import { createTokenManager } from "@common/auth"; export const tokenManager = createTokenManager(authConfig); export const { getToken, setToken, removeToken, setupRefreshTimer, clearAuthToken, getAccessToken, getRefreshToken, getUserId, } = tokenManager; ``` ### 3-4. 로그인 성공 처리 표준화 (`entities/auth/api/login-service.ts`) 로그인 성공 시 토큰 저장과 자동 갱신 타이머 설정을 한 흐름으로 고정한다. 예시 코드: ```ts import { getRemainingMs } from "@common/auth"; import { setToken, setupRefreshTimer } from "../lib/token-manager"; async function onLoginSuccess(params: { accessToken: string; tokenId: string; refresh: () => Promise; }) { setToken(authConfig.claimName, params.accessToken); setToken(authConfig.authUserId, params.tokenId); const remainingMs = getRemainingMs(params.accessToken); if (remainingMs <= 0) return; setupRefreshTimer(params.refresh, remainingMs); } ``` ### 3-5. 토큰 갱신 실패 처리 표준화 토큰 갱신 실패 시 인증 토큰을 일괄 정리한다. 예시 코드: ```ts import { clearAuthToken } from "../lib/token-manager"; async function silentRefresh() { try { ... } catch (error) { clearAuthToken(); throw error; } } ``` ### 3-6. 공통 레이아웃/쉘에 토큰 매니저 주입 공통 컴포넌트가 인증 기능을 직접 사용할 수 있도록 주입한다. 예시 코드: ```tsx import { tokenManager } from "@/entities/auth"; export function AppLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` ### 3-7. 배럴 파일 re-export 정리 (`entities/auth/index.ts`) 외부에서 인증 엔티티를 일관된 경로로 사용하도록 re-export한다. 예시 코드: ```ts export { LoginApi } from "./api/login-service"; export { AuthWrapper } from "./lib/auth-wrapper"; export { tokenManager } from "./lib/token-manager"; ``` ## 4) 서비스별 적용 체크리스트 각 서비스 담당자는 아래 항목을 모두 충족해야 한다. - `authConfig`에 서비스별 키명이 정확히 매핑되어 있다. - 서비스 내부 커스텀 TokenManager 클래스가 제거되었다. - 로그인/갱신 로직이 `getRemainingMs` 기반 타이머를 사용한다. - BaseLayout 컴포넌트에 `tokenManager`가 주입되어 있다. - 외부 참조 경로가 `entities/auth` 배럴 경로로 통일되어 있다.