Skip to content

fix: 헤더 임시 하드토큰 반영 로직 추가#115

Merged
heeeeyong merged 2 commits intodevelopfrom
feat/api-auth
Aug 13, 2025
Merged

fix: 헤더 임시 하드토큰 반영 로직 추가#115
heeeeyong merged 2 commits intodevelopfrom
feat/api-auth

Conversation

@heeeeyong
Copy link
Collaborator

@heeeeyong heeeeyong commented Aug 13, 2025

#️⃣연관된 이슈

ex) #이슈번호, #이슈번호

📝작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

스크린샷 (선택)

💬리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

Summary by CodeRabbit

  • New Features

    • 화면 우측 상단에 토큰 상태 배지 추가: Authorization 쿠키 유무를 표시하고 5초 간격으로 상태 갱신.
  • Improvements

    • Authorization 쿠키가 없을 때 임시 토큰을 자동 적용해 서비스 이용 중단 방지.
    • 로그인 토큰 발급 실패나 키 누락 시 페이지 이탈 없이 임시 토큰으로 계속 동작.
    • 로그인 실패 후 불필요한 쿼리 매개변수(code 등)를 자동 정리.

@vercel
Copy link

vercel bot commented Aug 13, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
thip Ready Preview Comment Aug 13, 2025 6:11pm

@coderabbitai
Copy link

coderabbitai bot commented Aug 13, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

임시 하드코드 JWT를 폴백으로 사용하는 요청 인터셉터가 추가되고, Authorization 쿠키 유무를 상시 표시하는 UI 배지가 추가되었습니다. useOAuthToken 훅은 발급 실패 시 리다이렉트 대신 임시 토큰으로 폴백하고 URL의 code 쿼리 파라미터를 제거합니다.

Changes

Cohort / File(s) Summary
API 클라이언트 인증 폴백
src/api/index.ts
요청 인터셉터 추가: document.cookie에서 Authorization= 쿠키 확인. 쿠키가 없으면 Authorization: Bearer TEMP_ACCESS_TOKEN 헤더를 주입하고 로그 출력. 쿠키가 있으면 자동 전송 로그. 응답 인터셉터 기존 동작 유지(401 리다이렉트는 주석 처리).
토큰 상태 배지 UI
src/components/common/TokenStatus.tsx
신규 컴포넌트 추가: 우측 상단 고정 배지로 토큰 쿠키 상태 표시(초기 '확인 중...' → '✅ Authorization 쿠키 있음' 또는 '🔑 임시 토큰 사용 중'), 5초 간격 재확인 및 언마운트 시 인터벌 정리.
OAuth 토큰 훅 폴백/정리
src/hooks/useOAuthToken.ts
토큰 발급 실패 또는 loginTokenKey 없음 시 루트('/') 리다이렉트 제거. 실패/부재 시 임시 토큰 사용 로그 출력 및 URL에서 code 쿼리 파라미터 제거(window.history.replaceState). 훅의 공개 시그니처 변경 없음.

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI/Component
  participant API as apiClient
  participant RI as Request Interceptor
  participant S as Server
  participant ResI as Response Interceptor

  UI->>API: API 요청
  API->>RI: 요청 인터셉션
  alt Authorization 쿠키 없음
    RI->>API: 헤더에 Bearer TEMP_ACCESS_TOKEN 설정
  else 쿠키 있음
    RI->>API: 헤더 변경 없이 진행 (브라우저가 쿠키 전송)
  end
  API->>S: 요청 전송
  S-->>API: 응답
  API->>ResI: 응답 인터셉션
  ResI-->>UI: 응답 전달
Loading
sequenceDiagram
  participant App as App
  participant Hook as useOAuthToken
  participant Auth as Auth Server

  App->>Hook: 훅 초기화
  alt loginTokenKey 없음
    Hook->>Hook: 임시 토큰 사용 로깅
    Hook->>Hook: URL 코드 파라미터 제거 (replaceState)
  else loginTokenKey 있음
    Hook->>Auth: 토큰 발급 시도
    alt 성공
      Auth-->>Hook: 토큰 반환
      Hook->>Hook: 정상 흐름 유지
    else 실패
      Auth-->>Hook: 오류
      Hook->>Hook: 임시 토큰 사용 로깅
      Hook->>Hook: URL 코드 파라미터 제거 (replaceState)
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Possibly related PRs

Suggested labels

✨ Feature

Poem

토큰이 없을 땐 난 깡충, 임시 열쇠로 뚜벅뚜벅,
우측 배지 반짝, 쿠키 있나 확인 중,
코드 쓱 지워 길 닦고 요청은 계속,
깡총! 안전하게 달려가라, 당근은 기다려 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 857ed60 and 8d3e6ab.

📒 Files selected for processing (1)
  • src/components/common/TokenStatus.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/api-auth

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@heeeeyong heeeeyong self-assigned this Aug 13, 2025
@heeeeyong heeeeyong added the 🐞 BugFix Something isn't working label Aug 13, 2025
@heeeeyong heeeeyong merged commit f3ab7e1 into develop Aug 13, 2025
1 of 2 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/components/common/TokenStatus.tsx (2)

7-18: 토큰 확인 로직을 API와 일치시키세요.

src/api/index.ts와 동일한 쿠키 파싱 로직을 사용하여 일관성을 보장하는 것이 좋습니다.

공통 유틸리티 함수를 만들어 재사용하는 것을 제안합니다:

// src/utils/cookie.ts
export const getCookie = (name: string): string | null => {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop()?.split(';').shift() || null;
  return null;
};

그리고 컴포넌트에서 사용:

+import { getCookie } from '@/utils/cookie';

 const checkToken = () => {
-  const cookies = document.cookie.split(';');
-  const hasAuthCookie = cookies.some(cookie => 
-    cookie.trim().startsWith('Authorization=')
-  );
+  const authCookie = getCookie('Authorization');
   
-  if (hasAuthCookie) {
+  if (authCookie) {
     setTokenStatus('✅ Authorization 쿠키 있음');
   } else {
     setTokenStatus('🔑 임시 토큰 사용 중');
   }
 };

27-42: 인라인 스타일을 CSS 모듈이나 styled-components로 개선하세요.

인라인 스타일보다는 더 유지보수가 쉬운 스타일링 방식을 사용하는 것이 좋습니다.

CSS 모듈을 사용한 예시:

// TokenStatus.module.css
.tokenStatus {
  position: fixed;
  top: 10px;
  right: 10px;
  background: #333;
  color: white;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 12px;
  z-index: 9999;
  font-family: monospace;
}
+import styles from './TokenStatus.module.css';

-  return (
-    <div style={{
-      position: 'fixed',
-      top: '10px',
-      right: '10px',
-      background: '#333',
-      color: 'white',
-      padding: '8px 12px',
-      borderRadius: '4px',
-      fontSize: '12px',
-      zIndex: 9999,
-      fontFamily: 'monospace'
-    }}>
+  return (
+    <div className={styles.tokenStatus}>
       {tokenStatus}
     </div>
   );
src/hooks/useOAuthToken.ts (1)

31-36: URL 정리 로직을 공통 함수로 분리하세요.

동일한 URL 정리 로직이 성공/실패 케이스에서 반복됩니다.

다음과 같이 공통 함수로 분리할 수 있습니다:

+  const cleanupUrl = () => {
+    const newUrl = window.location.pathname;
+    window.history.replaceState({}, document.title, newUrl);
+  };

   // 서버에 토큰 발급 요청
   apiClient
     .post('/api/set-cookie', { loginTokenKey }, { withCredentials: true })
     .then(response => {
       console.log('✅ 토큰 발급 성공:', response.data);
-      // URL에서 code 파라미터 제거
-      const newUrl = window.location.pathname;
-      window.history.replaceState({}, document.title, newUrl);
+      cleanupUrl();
     })
     .catch(error => {
       console.error('❌ 토큰 발급 실패:', error);
-      // navigate('/');
       console.log('💡 임시 토큰을 사용하여 계속 진행합니다.');
-      // 에러 발생 시에도 임시 토큰으로 계속 진행
-      // URL에서 code 파라미터 제거
-      const newUrl = window.location.pathname;
-      window.history.replaceState({}, document.title, newUrl);
+      cleanupUrl();
     });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95f5a9e and 857ed60.

📒 Files selected for processing (3)
  • src/api/index.ts (1 hunks)
  • src/components/common/TokenStatus.tsx (1 hunks)
  • src/hooks/useOAuthToken.ts (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.27.2)
src/api/index.ts

18-18: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


17-18: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (4)
src/api/index.ts (1)

42-52: 401 에러 처리 로직을 완성하거나 제거하세요.

주석 처리된 리다이렉트 로직이 있어서 혼란을 줄 수 있습니다. 임시 토큰 사용 시나리오에서 401 에러 처리 방식을 명확히 정의해야 합니다.

현재 임시 토큰 사용 시 401 에러가 발생할 경우 어떻게 처리해야 하는지 확인이 필요합니다. 다음 중 하나를 선택해주세요:

  1. 임시 토큰도 실패 시 로그인 페이지로 리다이렉트
  2. 401 에러 처리를 상위 컴포넌트에 위임
  3. 다른 처리 방식

결정에 따라 해당 로직을 구현하거나 주석을 제거하겠습니다.

src/components/common/TokenStatus.tsx (1)

1-25: 컴포넌트 구현이 잘 되었습니다.

토큰 상태를 실시간으로 모니터링하고 UI로 표시하는 기능이 잘 구현되었습니다. useEffect 클린업과 인터벌 관리도 적절합니다.

src/hooks/useOAuthToken.ts (2)

28-37: 에러 처리 개선이 잘 되었습니다.

로그인 실패 시 임시 토큰으로 폴백하는 로직이 잘 구현되었고, URL 정리도 적절히 수행됩니다.


38-40: 로직이 올바르게 구현되었습니다.

loginTokenKey가 없는 경우에 대한 처리가 명확하게 추가되었습니다.

Comment on lines +16 to +18
// 임시 하드코딩된 토큰 (쿠키가 없을 때 사용)
const TEMP_ACCESS_TOKEN =
'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImlhdCI6MTc1NDM4MjY1MiwiZXhwIjoxNzU2OTc0NjUyfQ.BSGuoMWlrzc0oKgSJXHEycxdzzY9-e7gD4xh-wSDemc';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

하드코딩된 JWT 토큰을 환경변수로 이동하세요.

프로덕션 환경에서 JWT 토큰이 소스 코드에 하드코딩되어 있으면 보안 위험이 됩니다. 또한 정적 분석 도구에서도 이를 보안 위험으로 탐지하고 있습니다.

다음과 같이 환경변수로 이동하는 것을 권장합니다:

-// 임시 하드코딩된 토큰 (쿠키가 없을 때 사용)
-const TEMP_ACCESS_TOKEN =
-  'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImlhdCI6MTc1NDM4MjY1MiwiZXhwIjoxNzU2OTc0NjUyfQ.BSGuoMWlrzc0oKgSJXHEycxdzzY9-e7gD4xh-wSDemc';
+// 임시 토큰 (쿠키가 없을 때 사용)
+const TEMP_ACCESS_TOKEN = import.meta.env.VITE_TEMP_ACCESS_TOKEN || '';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 임시 하드코딩된 토큰 (쿠키가 없을 때 사용)
const TEMP_ACCESS_TOKEN =
'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImlhdCI6MTc1NDM4MjY1MiwiZXhwIjoxNzU2OTc0NjUyfQ.BSGuoMWlrzc0oKgSJXHEycxdzzY9-e7gD4xh-wSDemc';
// 임시 토큰 (쿠키가 없을 때 사용)
const TEMP_ACCESS_TOKEN = import.meta.env.VITE_TEMP_ACCESS_TOKEN || '';
🧰 Tools
🪛 Gitleaks (8.27.2)

18-18: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


17-18: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
In src/api/index.ts around lines 16 to 18, the JWT access token is hardcoded
which is a security risk; remove the literal string and instead read the token
from an environment variable (e.g. process.env.TEMP_ACCESS_TOKEN or a clearer
name like process.env.DEFAULT_ACCESS_TOKEN), validate that the env var exists at
startup and fail fast or log a clear error if missing, and ensure any defaults
are not sensitive values (no hardcoded fallback); update any documentation and
deployment configs to set the new env var.

Comment on lines +21 to +40
apiClient.interceptors.request.use(
config => {
// 쿠키에서 Authorization 확인
const cookies = document.cookie.split(';');
const hasAuthCookie = cookies.some(cookie => cookie.trim().startsWith('Authorization='));

// 쿠키가 없으면 임시 토큰을 헤더에 추가
if (!hasAuthCookie) {
console.log('🔑 쿠키가 없어서 임시 토큰을 헤더에 추가합니다.');
config.headers.Authorization = `Bearer ${TEMP_ACCESS_TOKEN}`;
} else {
console.log('✅ Authorization 쿠키가 있어서 자동으로 전송됩니다.');
}

return config;
},
error => {
return Promise.reject(error);
},
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

토큰 확인 로직을 개선하세요.

현재 구현에 다음과 같은 문제점이 있습니다:

  1. 쿠키 파싱 로직이 정확하지 않을 수 있습니다 (공백 처리 등)
  2. 빈 임시 토큰에 대한 검증이 없습니다
  3. 로깅이 과도할 수 있습니다

다음과 같이 개선된 구현을 제안합니다:

 // Request 인터셉터: 쿠키가 없을 때 임시 토큰을 헤더에 추가
 apiClient.interceptors.request.use(
   config => {
-    // 쿠키에서 Authorization 확인
-    const cookies = document.cookie.split(';');
-    const hasAuthCookie = cookies.some(cookie => cookie.trim().startsWith('Authorization='));
+    // 쿠키에서 Authorization 확인
+    const getCookie = (name: string) => {
+      const value = `; ${document.cookie}`;
+      const parts = value.split(`; ${name}=`);
+      if (parts.length === 2) return parts.pop()?.split(';').shift();
+      return null;
+    };
+    
+    const authCookie = getCookie('Authorization');

-    // 쿠키가 없으면 임시 토큰을 헤더에 추가
-    if (!hasAuthCookie) {
-      console.log('🔑 쿠키가 없어서 임시 토큰을 헤더에 추가합니다.');
-      config.headers.Authorization = `Bearer ${TEMP_ACCESS_TOKEN}`;
+    // 쿠키가 없으면 임시 토큰을 헤더에 추가
+    if (!authCookie && TEMP_ACCESS_TOKEN) {
+      if (process.env.NODE_ENV === 'development') {
+        console.log('🔑 쿠키가 없어서 임시 토큰을 헤더에 추가합니다.');
+      }
+      config.headers.Authorization = `Bearer ${TEMP_ACCESS_TOKEN}`;
-    } else {
-      console.log('✅ Authorization 쿠키가 있어서 자동으로 전송됩니다.');
+    } else if (authCookie && process.env.NODE_ENV === 'development') {
+      console.log('✅ Authorization 쿠키가 있어서 자동으로 전송됩니다.');
     }

     return config;
   },
   error => {
     return Promise.reject(error);
   },
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
apiClient.interceptors.request.use(
config => {
// 쿠키에서 Authorization 확인
const cookies = document.cookie.split(';');
const hasAuthCookie = cookies.some(cookie => cookie.trim().startsWith('Authorization='));
// 쿠키가 없으면 임시 토큰을 헤더에 추가
if (!hasAuthCookie) {
console.log('🔑 쿠키가 없어서 임시 토큰을 헤더에 추가합니다.');
config.headers.Authorization = `Bearer ${TEMP_ACCESS_TOKEN}`;
} else {
console.log('✅ Authorization 쿠키가 있어서 자동으로 전송됩니다.');
}
return config;
},
error => {
return Promise.reject(error);
},
);
apiClient.interceptors.request.use(
config => {
// 쿠키에서 Authorization 확인
const getCookie = (name: string) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop()?.split(';').shift();
return null;
};
const authCookie = getCookie('Authorization');
// 쿠키가 없으면 임시 토큰을 헤더에 추가
if (!authCookie && TEMP_ACCESS_TOKEN) {
if (process.env.NODE_ENV === 'development') {
console.log('🔑 쿠키가 없어서 임시 토큰을 헤더에 추가합니다.');
}
config.headers.Authorization = `Bearer ${TEMP_ACCESS_TOKEN}`;
} else if (authCookie && process.env.NODE_ENV === 'development') {
console.log('✅ Authorization 쿠키가 있어서 자동으로 전송됩니다.');
}
return config;
},
error => {
return Promise.reject(error);
},
);
🤖 Prompt for AI Agents
In src/api/index.ts around lines 21 to 40, improve the token-checking logic:
parse document.cookie robustly by splitting on ';' then mapping/trimming each
pair and comparing key names exactly (e.g. cookie.split('=').map(s =>
s.trim())), check if config.headers and config.headers.Authorization already
exist before setting anything (ensure config.headers = config.headers || {}),
only set Authorization to `Bearer ${TEMP_ACCESS_TOKEN}` if no Authorization
cookie and TEMP_ACCESS_TOKEN is a non-empty string, and remove or reduce
console.log noise (use a single debug log or none); also preserve existing
header values and return config as before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 BugFix Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant