Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ import axios, {
AxiosRequestConfig,
AxiosResponse,
InternalAxiosRequestConfig,
RawAxiosRequestHeaders,
} from "axios";

/** API 사용 전, ENV 파일을 통해 서버 연동 설정을 해주세요 */
const API_URL = import.meta.env.VITE_API_URL as string;

const baseApi = axios.create({
baseURL: API_URL,
timeout: 5000,
const headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};

headers: {
"Content-Type": "application/json",
},
const token = localStorage.getItem(ACCESS_TOKEN);
if (token) {
headers.Authorization = `Bearer ${token}`;
}
Comment on lines +15 to +22
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove duplicate Authorization header logic.

The Authorization header is being set twice:

  1. Here at instance creation (lines 19-22)
  2. In the request interceptor (lines 51-54)

The static header setting at instance creation won't update when the token changes, making it unreliable. The request interceptor already handles this correctly by reading the fresh token on each request.

-const headers: RawAxiosRequestHeaders = {
-  "Content-Type": "application/json",
-};
-
-const token = localStorage.getItem(ACCESS_TOKEN);
-if (token) {
-  headers.Authorization = `Bearer ${token}`;
-}
+const headers: RawAxiosRequestHeaders = {
+  "Content-Type": "application/json",
+};
📝 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 headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};
headers: {
"Content-Type": "application/json",
},
const token = localStorage.getItem(ACCESS_TOKEN);
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};
🤖 Prompt for AI Agents
In src/api/index.ts around lines 15 to 22, remove the logic that sets the
Authorization header using the token from localStorage during instance creation.
This is redundant because the request interceptor (lines 51-54) already sets the
Authorization header dynamically on each request with the latest token. Deleting
this static header assignment ensures the Authorization header always uses the
current token.


const axiosInstance = axios.create({
baseURL: API_URL,
headers,
withCredentials: true, // CORS 쿠키 전송을 위해 필요
});

/** 개발 환경에서만 실행되논 로깅 함수 */
Expand Down Expand Up @@ -120,11 +127,11 @@ const onErrorResponse = (error: AxiosError | Error) => {
};

/** 인터셉터를 설정 하고, Axios Instance를 반환하는 함수 */
const setInterceptors = (axiosInstance: AxiosInstance): AxiosInstance => {
axiosInstance.interceptors.request.use(onRequest, onErrorRequest);
axiosInstance.interceptors.response.use(onResponse, onErrorResponse);
const setInterceptors = (instance: AxiosInstance): AxiosInstance => {
instance.interceptors.request.use(onRequest, onErrorRequest);
instance.interceptors.response.use(onResponse, onErrorResponse);

return axiosInstance;
return instance;
};

export const api = setInterceptors(baseApi);
export const api = setInterceptors(axiosInstance);
29 changes: 17 additions & 12 deletions src/app/oauth2/redierct/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import { loginState } from "@/store/user";
import { ACCESS_TOKEN } from "@/utils/constant";
import { useSetAtom } from "jotai";
import { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { useSetAtom } from "jotai";
import { loginState, tokenState } from "@/store/user";
import { ACCESS_TOKEN } from "@/utils/constant";

export default function Oauth2Redirect() {
const location = useLocation();
const navigate = useNavigate();
const params = new URLSearchParams(location.search);
const accessToken = params.get("accessToken");
const setLogin = useSetAtom(loginState);
const setToken = useSetAtom(tokenState);

useEffect(() => {
if (accessToken) {
localStorage.setItem(ACCESS_TOKEN, accessToken);
const params = new URLSearchParams(window.location.search);
const token = params.get("token");

if (token) {
localStorage.setItem(ACCESS_TOKEN, token);
setToken(token);
Comment on lines +17 to +18
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Critical: Token key inconsistency between localStorage and atom state.

There's a mismatch in token storage keys:

  • localStorage.setItem(ACCESS_TOKEN, token) uses the ACCESS_TOKEN constant
  • setToken(token) sets the tokenState atom which uses "accessToken" as the storage key
  • The relevant code snippet shows ACCESS_TOKEN = "access_token" (with underscore)

This inconsistency will cause synchronization issues between localStorage and the atom state.

To fix this, either:

  1. Use the same key for both storage mechanisms, or
  2. Use only the atom state and let atomWithStorage handle localStorage automatically
-      localStorage.setItem(ACCESS_TOKEN, token);
-      setToken(token);
+      setToken(token); // atomWithStorage will handle localStorage automatically

🏁 Script executed:

#!/bin/bash
# Verify the ACCESS_TOKEN constant value and usage across the codebase
echo "Checking ACCESS_TOKEN constant definition:"
rg "ACCESS_TOKEN.*=" --type ts

echo -e "\nChecking ACCESS_TOKEN usage:"
rg "ACCESS_TOKEN" --type ts -A 2 -B 2

Length of output: 3738


🏁 Script executed:

#!/bin/bash
# Search for tokenState definition in the codebase
rg "tokenState" -n --type ts

# Show the file containing tokenState to inspect its definition
rg -A5 "tokenState" --type ts

Length of output: 1207


Ensure consistent token storage key across localStorage and atom state

The ACCESS_TOKEN constant is defined as btoa("FLOWBIT_ACT") (e.g. "RkxPV0JJVF9BQ1Q="), while your tokenState atom persists under "accessToken". This means:

  • API calls (localStorage.getItem(ACCESS_TOKEN)) will never see the value stored by atomWithStorage("accessToken", …)
  • atomWithStorage will never read or write the key your API relies on

To resolve, pick one shared key and apply it everywhere:

• src/utils/constant.ts

- const ACCESS_TOKEN = btoa("FLOWBIT_ACT");
+ export const ACCESS_TOKEN = "accessToken";

• src/store/user/index.ts

- export const tokenState = atomWithStorage("accessToken", "");
+ export const tokenState = atomWithStorage(ACCESS_TOKEN, "");

• src/app/oauth2/redirect/index.tsx

-      localStorage.setItem(ACCESS_TOKEN, token);
-      setToken(token);
+      setToken(token); // atomWithStorage will now handle both state and localStorage under ACCESS_TOKEN

Or, if you prefer to keep the base64 key, swap the "accessToken" literal in your atom to use ACCESS_TOKEN instead, and remove direct localStorage calls in favor of setToken(token).

🤖 Prompt for AI Agents
In src/app/oauth2/redierct/index.tsx around lines 17 to 18, there is an
inconsistency between the localStorage key ACCESS_TOKEN and the atom state key
"accessToken" used by tokenState. To fix this, unify the storage key by either
changing the atomWithStorage key to use ACCESS_TOKEN or by removing direct
localStorage calls and relying solely on the atomWithStorage state with the
ACCESS_TOKEN key. Ensure that both localStorage and atom state use the exact
same key constant to maintain synchronization.

setLogin(true);
navigate("/");
} else {
alert("오류가 발생했어요, 관리자에게 문의해주세요");
// 토큰이 없는 경우 에러 처리
setLogin(false);
setToken("");
navigate("/signin");
}
}, []);
}, [navigate, setLogin, setToken]);

return <>처리중입니다.</>;
return null;
}
3 changes: 2 additions & 1 deletion src/store/user/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { atomWithStorage } from "jotai/utils";

export const loginState = atomWithStorage("isLogin", false);
export const loginState = atomWithStorage("isLogin", false);
export const tokenState = atomWithStorage("accessToken", "");