Skip to content

Conversation

@minwoo1999
Copy link
Member

@minwoo1999 minwoo1999 commented May 25, 2025

소셜로그인 이후 토큰이 있어도 401로 떨어지는 현상해결

목적

  • 소셜로그인 후 토큰이 정상적으로 존재함에도 401 인증 오류가 발생하는 현상 수정
  • 세션 유지 문제 해결

작업 내용

  1. API 요청 시 인증 헤더 설정 방식 개선

    • withCredentials 옵션 추가로 CORS 쿠키 전송 활성화
    • Authorization 헤더 설정 로직 통합
  2. OAuth2 리다이렉트 처리 로직 개선

    • 토큰 저장 및 상태 관리 로직 수정
    • 에러 처리 로직 강화
  3. 토큰 관리 방식 일원화

    • localStorage와 Jotai state 동기화 처리
    • 토큰 관련 상태 관리 개선

필수 리뷰어

이슈 번호

Summary by CodeRabbit

  • Refactor
    • Improved the handling and storage of authentication tokens for API requests and OAuth2 redirects.
    • Updated internal logic to enhance token management and navigation after authentication.
  • New Features
    • Added persistent storage for user tokens, allowing for smoother login experiences across sessions.

소셜로그인 이후 토큰이 있어도 401로 떨어지는 현상해결
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 25, 2025

Walkthrough

The changes refactor API instance creation and token handling by explicitly configuring Axios headers and updating token storage logic. The OAuth2 redirect component now reads the token from a different query parameter, saves it in localStorage, and synchronizes it with a new atom state. A new atom for token management is introduced.

Changes

File(s) Summary
src/api/index.ts Refactored Axios instance creation, added explicit headers, conditional Authorization, renamed variables, and updated export.
src/app/oauth2/redierct/index.tsx Changed token extraction to use window.location.search, updated parameter key, synchronized token and login state, removed alert, updated effect dependencies, and changed render output to null.
src/store/user/index.ts Added new exported atom tokenState for managing "accessToken" in localStorage.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant Oauth2Redirect
    participant LocalStorage
    participant UserStore
    participant Router

    Browser->>Oauth2Redirect: Loads with ?token=...
    Oauth2Redirect->>Browser: Reads token from window.location.search
    Oauth2Redirect->>LocalStorage: Stores token under "accessToken"
    Oauth2Redirect->>UserStore: Sets loginState and tokenState
    Oauth2Redirect->>Router: Navigates to "/"
Loading
sequenceDiagram
    participant App
    participant AxiosInstance
    participant LocalStorage

    App->>LocalStorage: Reads "accessToken"
    App->>AxiosInstance: Creates instance with headers (Authorization if token exists)
    AxiosInstance-->>App: Ready for authenticated API calls
Loading

Assessment against linked issues

Objective Addressed Explanation
Fix issue where user receives 401 after social login even when token exists (#105)

Possibly related PRs

Suggested reviewers

  • Cllaude99
  • joeunSong

Poem

A token hops from query to store,
Now Axios knows what’s in store!
With headers set and atoms new,
The login flow is smooth and true.
No more 401s to fear—
The bunny’s code brings access near!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

Copy link
Contributor

@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 (1)
src/app/oauth2/redierct/index.tsx (1)

29-29: Consider showing loading state during redirect processing.

Returning null means users won't see any feedback during the OAuth2 redirect processing. Consider showing a loading indicator for better UX.

-  return null;
+  return <div>Processing login...</div>;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e120ea and 72e162e.

📒 Files selected for processing (3)
  • src/api/index.ts (2 hunks)
  • src/app/oauth2/redierct/index.tsx (1 hunks)
  • src/store/user/index.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/app/oauth2/redierct/index.tsx (2)
src/store/user/index.ts (2)
  • loginState (3-3)
  • tokenState (4-4)
src/utils/constant.ts (1)
  • ACCESS_TOKEN (16-16)
src/api/index.ts (1)
src/utils/constant.ts (1)
  • ACCESS_TOKEN (16-16)
🔇 Additional comments (6)
src/store/user/index.ts (1)

3-4: LGTM! Clean token state management implementation.

The new tokenState atom using atomWithStorage provides a clean way to manage token persistence. The implementation correctly uses the same storage key ("accessToken") and initializes with an appropriate default value.

src/app/oauth2/redierct/index.tsx (2)

13-14: Verify the URL parameter change from "accessToken" to "token".

The parameter extraction has changed from "accessToken" to "token". Please confirm this aligns with the OAuth2 provider's redirect URL format.


22-26: Good error handling improvement.

The error handling now properly clears both login and token states, which ensures a clean state when authentication fails.

src/api/index.ts (3)

27-27: Excellent addition for CORS cookie support.

The withCredentials: true option is essential for enabling CORS cookie transmission, which helps resolve authentication issues in cross-origin scenarios.


51-54: Good token handling in request interceptor.

The request interceptor correctly reads the fresh token from localStorage on each request, ensuring the Authorization header is always up-to-date.


130-137: Clean refactoring of interceptor setup.

The parameter renaming from axiosInstance to instance improves clarity and avoids confusion with the module-level variable.

Comment on lines +17 to +18
localStorage.setItem(ACCESS_TOKEN, token);
setToken(token);
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.

Comment on lines +15 to +22
const headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};

headers: {
"Content-Type": "application/json",
},
const token = localStorage.getItem(ACCESS_TOKEN);
if (token) {
headers.Authorization = `Bearer ${token}`;
}
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.

Copy link
Contributor

@joeunSong joeunSong left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~

@minwoo1999 minwoo1999 merged commit e9dff9c into main May 29, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

소셜 로그인 이후 토큰 값이 있는 경우에도 401로 떨어지는 현상 수정

3 participants