Skip to content

[Refactor] 알림 SSE 훅 구조 개선 및 타입 단순화#391

Merged
Chiman2937 merged 5 commits intomainfrom
chiyoung-refactor/notification
Feb 23, 2026
Merged

[Refactor] 알림 SSE 훅 구조 개선 및 타입 단순화#391
Chiman2937 merged 5 commits intomainfrom
chiyoung-refactor/notification

Conversation

@Chiman2937
Copy link
Member

@Chiman2937 Chiman2937 commented Feb 23, 2026

📝 변경 사항

알림 SSE 훅 리팩토링 변경사항

브랜치: chiyoung-refactor/notification
커밋 범위: 5a07052 ~ 822081e (5개 커밋)
변경 파일: 7개 (173 additions, 175 deletions)


커밋 히스토리

커밋 메시지
5a07052 fix: notification type 간소화
4854e4c refactor: useConnectSSE 역할 분리
9747281 fix: providers - NotificationProvider: hasRefreshToken props 삭제
5fe306d fix: useSSEConnect - onError retry 가드 추가
822081e fix: 언마운트된 컴포넌트에서의 reconnect 실행을 방지하기 위한 가드 로직 추가

1. useConnectSSE 역할 분리

기존 useConnectSSE 훅이 SSE 연결 관리와 알림 이벤트 처리(쿼리 무효화)를 모두 담당하고 있었으나, 이를 연결 전용(useSSEConnect)과 이벤트 처리 전용(useSSEEvent) 두 훅으로 분리.

Before - 단일 훅에서 모든 역할 수행

src/hooks/use-notification/
  └── use-notification-connect-sse/index.ts  ← 146줄, 연결 + 이벤트 처리 모두 담당

After - 역할별 분리

src/hooks/use-sse/
  ├── index.ts                        ← re-export
  ├── use-sse-connect/index.ts        ← SSE 연결/해제/재연결 관리 (111줄)
  └── use-sse-event/index.ts          ← SSE 이벤트 수신 시 쿼리 무효화 처리 (38줄)
역할 반환값
useSSEConnect SSE 연결/해제/재연결, 수신 데이터 상태 관리 { data: NotificationItem | null }
useSSEEvent 수신된 데이터 기반 쿼리 무효화(invalidation) 없음

useSSEConnect 변경점

  • isAuthenticated 체크 로직 제거 → 연결 관리에만 집중
  • hasRefreshToken 파라미터 제거
  • receivedNewNotification 상태 → data 상태로 변경 (수신된 NotificationItem 자체를 관리)
  • connect()/disconnect()를 외부에 노출하지 않고 내부 useEffect에서 자동 관리

useSSEEvent - 쿼리 무효화 로직을 선언적 Map으로 전환

기존 switch-case 구문을 SSE_INVALIDATION_MAP 객체로 변환하여 선언적으로 관리.

// Before - switch-case
switch (data.type) {
  case 'FOLLOW':
    queryClient.invalidateQueries({ queryKey: userKeys.me() });
    queryClient.invalidateQueries({ queryKey: userKeys.item(data.user.id) });
    break;
  case 'GROUP_CREATE':
  case 'GROUP_DELETE':
    queryClient.invalidateQueries({ queryKey: groupKeys.lists() });
    break;
  // ...
}

// After - 선언적 Map
const SSE_INVALIDATION_MAP: Partial<
  Record<NotificationItem['type'], (data: NotificationItem) => QueryKey[]>
> = {
  FOLLOW: (data) => [userKeys.me(), userKeys.item(data.user.id)],
  GROUP_CREATE: () => [groupKeys.lists()],
  GROUP_DELETE: () => [groupKeys.lists()],
  GROUP_JOIN: (data) => (data.group ? [groupKeys.detail(String(data.group.id))] : []),
  // ...
};

2. Notification Type 간소화

src/types/service/notification.ts에서 Discriminated Union 패턴을 제거하고 단일 NotificationItem 인터페이스로 통합.

Before - Discriminated Union (3개 타입)

type NotificationTypeWithoutGroup = 'FOLLOW';
type NotificationTypeWithGroup = Exclude<NotificationType, NotificationTypeWithoutGroup>;

interface BaseNotification {
  id: number;
  message: string;
  readAt: string | null;
  createdAt: string;
  user: { id: number; nickname: string; };
}

interface NotificationWithoutGroup extends BaseNotification {
  type: NotificationTypeWithoutGroup;
  group: null;
}

interface NotificationWithGroup extends BaseNotification {
  type: NotificationTypeWithGroup;
  group: { id: number; title: string; } | null;
}

export type NotificationItem = NotificationWithoutGroup | NotificationWithGroup;

After - 단일 인터페이스

export interface NotificationItem {
  id: number;
  message: string;
  readAt: string | null;
  createdAt: string;
  type: NotificationType;
  user: { id: number; nickname: string; };
  group: { id: number; title: string; } | null;
}

FOLLOW 타입일 때 groupnull이라는 것을 타입 레벨에서 강제할 필요 없이, 런타임에서 group 존재 여부만 체크하면 충분하므로 간소화.


3. NotificationProvider 간소화

src/providers/provider-notification/index.tsx에서 분리된 훅을 사용하도록 변경.

// Before
export const NotificationProvider = ({ children, hasRefreshToken }: NotificationProviderProps) => {
  const { data: unReadCount = 0 } = useGetNotificationUnreadCount();
  const { receivedNewNotification, connect, disconnect } = useConnectSSE(hasRefreshToken);

  useEffect(() => {
    connect();
    return () => { disconnect(); };
  }, []);
  // ...
};

// After
export const NotificationProvider = ({ children }: NotificationProviderProps) => {
  const { data: unReadCount = 0 } = useGetNotificationUnreadCount();
  const { data: receivedData } = useSSEConnect();
  useSSEEvent(receivedData);

  const receivedNewNotification = !!receivedData;
  // ...
};

변경점

  • hasRefreshToken props 제거
  • connect()/disconnect() 수동 호출 제거 → useSSEConnect 내부에서 자동 관리
  • useEffect 제거 → SSE 연결 생명주기가 훅 내부로 캡슐화됨

4. useSSEConnect 안정성 개선

SSE 연결 오류 시 재연결 로직에 가드를 추가하여 안정성 개선.

onError retry 가드 추가

이미 retry 중일 때 onerror가 다시 발생해도 reconnect()가 중복 실행되지 않도록 가드 추가.

es.onerror = async (_error) => {
  console.log('[DEBUG] SSE - 연결 오류 발생');
  es.close();
  if (retryRefreshRef.current) return;  // 이미 retry 중이면 무시
  reconnect();
};

언마운트 가드 추가

컴포넌트 언마운트 이후 비동기 reconnect()가 완료되어 setupSSEConnection()이 호출되는 것을 방지하기 위해 isMountedRef 가드 추가.

const isMountedRef = useRef(true);

const setupSSEConnection = (token: string) => {
  if (!isMountedRef.current) {
    console.log('[DEBUG] SSE - 언마운트된 컴포넌트, 연결 중단');
    return;
  }
  // ...
};

useEffect(() => {
  isMountedRef.current = true;
  connect();
  return () => {
    isMountedRef.current = false;
    disconnect();
  };
}, []);

변경된 파일 목록

파일 변경 유형
src/hooks/use-notification/use-notification-connect-sse/index.ts 삭제
src/hooks/use-sse/index.ts 신규 (re-export)
src/hooks/use-sse/use-sse-connect/index.ts 신규 (SSE 연결 관리)
src/hooks/use-sse/use-sse-event/index.ts 신규 (SSE 이벤트 → 쿼리 무효화)
src/providers/provider-notification/index.tsx 수정 (분리된 훅 적용, hasRefreshToken 제거)
src/app/providers.tsx 수정 (NotificationProvider에서 hasRefreshToken props 제거)
src/types/service/notification.ts 수정 (Discriminated Union → 단일 인터페이스)

🔗 관련 이슈

Closes #


🧪 테스트 방법

  • 수동 테스트 검증(로컬 환경)
  • 유닛 테스트 검증
  • 통합 테스트 검증

📸 스크린샷 (선택)


📋 체크리스트

  • 관련 문서를 업데이트했습니다 (필요한 경우)
  • 테스트를 추가/수정했습니다 (필요한 경우)
  • Breaking change가 있다면 명시했습니다

💬 추가 코멘트


CodeRabbit Review는 자동으로 실행되지 않습니다.

Review를 실행하려면 comment에 아래와 같이 작성해주세요

@coderabbitai review

Summary by CodeRabbit

Release Notes

  • Refactor
    • 실시간 알림 수신 및 연결 관리 로직을 개선하여 시스템 안정성을 향상시켰습니다.
    • 알림 처리 메커니즘의 내부 구조를 최적화하여 코드 효율성을 개선했습니다.
    • 알림 데이터 타입 정의를 단순화하여 코드의 가독성과 유지보수성을 개선했습니다.

- useSSEConnect: SSE 연결 및 수신 Data 상태 저장만 담당
- useSSEEvent: data를 이용한 이벤트 처리만 담당
- NotificationProvider: useEffect의 connect, disconnect는 useSSEConnect
  훅으로 이관
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

SSE 연결 로직을 재구조화하여 단일 useConnectSSE 훅을 useSSEConnectuseSSEEvent 두 개의 새로운 훅으로 분리했습니다. NotificationProvider에서 hasRefreshToken prop을 제거하고, NotificationItem 타입을 합집합에서 인터페이스로 변경했습니다.

Changes

Cohort / File(s) Summary
SSE 연결 로직 재구조화
src/hooks/use-sse/use-sse-connect/index.ts, src/hooks/use-sse/use-sse-event/index.ts, src/hooks/use-sse/index.ts
기존 useConnectSSE 훅을 제거하고 새로운 useSSEConnect (EventSource 생명주기 관리 및 알림 데이터 상태 관리)와 useSSEEvent (React Query 캐시 무효화)로 분리. 총 111줄 추가 및 2줄 재수출.
NotificationProvider 업데이트
src/providers/provider-notification/index.tsx, src/app/providers.tsx
hasRefreshToken prop 제거, 새로운 훅 기반 SSE 연결 로직으로 교체, 알림 상태 유도 방식 변경.
이전 SSE 훅 제거
src/hooks/use-notification/use-notification-connect-sse/index.ts
전체 useConnectSSE 구현 및 SSE 생명주기, 토큰 갱신, 상태 관리, 쿼리 무효화 로직 제거 (146줄 삭제).
알림 타입 정의 개선
src/types/service/notification.ts
NotificationItem을 합집합 타입에서 단일 인터페이스로 변경하고, type: NotificationType 필드 추가; 보조 타입 선언 제거.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Ready For Review!

Suggested reviewers

  • wooktori

Poem

🐰 우리의 알림 흐름을 다시 짜네요,
한 훅을 둘로 나누어 정결하게,
SSE와 쿼리가 손잡고 춤을 춘답니다,
hasRefreshToken은 작별하고,
새로운 구조로 더욱 우아해져요! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed PR 제목은 변경 사항의 핵심을 명확하게 요약합니다. SSE 훅 구조 개선과 타입 단순화라는 두 가지 주요 변경을 간결하게 나타냅니다.
Description check ✅ Passed PR 설명이 템플릿의 모든 필수 섹션을 포함하고 있으며, 변경사항을 상세히 설명하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chiyoung-refactor/notification

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Feb 23, 2026

🎭 Playwright Report

E2E Test가 성공적으로 완료되었습니다.

Test 요약 내용을 확인해주세요.

Status Build Log Updated (UTC)
✅ Ready View Build 2026-02-23 12:09:00

📊 Test Summary

  • ✅ Passed: 3
  • ❌ Failed: 0
  • ⏱️ Duration: 39.0s

📜 Test Details

✅ Passed Tests (3)
  • profile.test.ts (3)
    • [chromium] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트
    • [firefox] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트
    • [webkit] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트

@github-actions
Copy link

github-actions bot commented Feb 23, 2026

📊 Coverage Report

Status Build Log Updated (UTC)
✅ Ready View Build 2026-02-23 12:07:33

📈 #391main에 병합하면 coverage가 0.18% 증가합니다.

Coverage 요약

@@             Coverage Diff             @@
##             main     #391       +/-   ##
===========================================
+ Coverage   35.40%   35.58%    +0.18%     
===========================================
  Files         262      264        +2     
  Lines       12119    12116        -3     
  Branches      467      467         0     
===========================================
+ Hits         4291     4312       +21     
- Misses       7828     7804       -24     

영향받은 파일

파일 Coverage 변화
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/hooks/use-sse/index.ts 100.00% (+100.00%) ⬆️
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/hooks/use-sse/use-sse-connect/index.ts 6.55% (+6.55%) ⬆️
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/hooks/use-sse/use-sse-event/index.ts 65.78% (+65.78%) ⬆️
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/providers/provider-notification/index.tsx 54.28% (+5.50%) ⬆️

@github-actions
Copy link

github-actions bot commented Feb 23, 2026

🚀 PR Preview Report

Build가 성공적으로 완료되었습니다.

Preview에서 변경사항을 확인하세요.

Status Preview Build Log Updated (UTC)
✅ Ready Visit Preview View Logs 2026-02-23 12:08:36

@github-actions
Copy link

github-actions bot commented Feb 23, 2026

🎨 Storybook Report

변경 사항이 없습니다

모든 Story가 이전 빌드와 동일합니다.

Status Storybook Build Log Updated (UTC)
✅ Unchanged View Storybook View Build 2026-02-23 12:08:50

@Chiman2937
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 3

🧹 Nitpick comments (2)
src/hooks/use-sse/use-sse-connect/index.ts (1)

15-92: 프로덕션 배포 전 [DEBUG] 로그 제거 필요

파일 전체에 걸쳐 [DEBUG] 접두사가 붙은 console.log / console.error 구문이 다수 존재합니다(Line 18, 28, 38, 47, 56, 62, 71, 80, 82, 88). 프로덕션 환경에서 민감한 SSE 연결 상태 정보가 콘솔에 노출됩니다. 제거하거나 구조화된 로깅 유틸리티로 교체하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/use-sse/use-sse-connect/index.ts` around lines 15 - 92, Replace all
raw console.log/console.error calls in connect, disconnect, reconnect, and
setupSSEConnection with production-safe logging: either remove the “[DEBUG]”
messages or route them through the app’s structured logger (e.g.,
logger.debug/info/error) and guard verbose debug logs behind an environment
check (NODE_ENV !== 'production' or a feature flag). Update uses around
eventSourceRef and retryRefreshRef (all console.* occurrences inside connect,
disconnect, reconnect, and setupSSEConnection) so no sensitive SSE state is
printed in production; ensure error paths still record enough context via the
structured logger.
src/hooks/use-sse/use-sse-event/index.ts (1)

28-37: queryClientuseEffect 의존성 배열에 추가하는 것을 고려하세요.

queryClient가 effect 내부에서 사용되지만 의존성 배열에 누락되어 react-hooks/exhaustive-deps 린트 경고가 발생합니다. @tanstack/react-query v5에서 queryClient는 안정적인 참조이므로 동작에는 문제없으나, 관례상 포함하는 것이 권장됩니다.

♻️ 제안: 의존성 배열에 queryClient 추가
-  }, [data]);
+  }, [data, queryClient]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/use-sse/use-sse-event/index.ts` around lines 28 - 37, The useEffect
uses queryClient (and SSE_INVALIDATION_MAP, notificationKeys, data) but omits
queryClient from its dependency array, causing a react-hooks/exhaustive-deps
lint warning; update the useEffect dependency array to include queryClient
(e.g., change [data] to [data, queryClient]) so the effect declares all external
references used inside (no other behavioral changes required since QueryClient
is stable in `@tanstack/react-query` v5).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/hooks/use-sse/use-sse-connect/index.ts`:
- Around line 87-91: The onerror handler for the EventSource (es.onerror) lacks
a guard for retryRefreshRef.current, which allows infinite reconnect loops;
update the es.onerror callback to check retryRefreshRef.current before calling
reconnect() (e.g., if (!retryRefreshRef.current) { reconnect(); }) so you only
trigger the reconnect path when allowed; locate es.onerror in use-sse-connect's
setupSSEConnection and reference retryRefreshRef and reconnect() to implement
the guard and preserve the existing console log and es.close() behavior.
- Around line 36-50: The reconnect function (reconnect) can resume after await
when the component may have unmounted; fix by checking the sentinel
retryRefreshRef.current immediately after the await API.authService.refresh()
(and before calling setupSSEConnection) and aborting if it has been cleared
(false), to avoid creating an EventSource for an unmounted component; also
ensure you still call disconnect() inside the catch path and only call
setupSSEConnection(token) when token exists and retryRefreshRef.current is true.
- Around line 63-65: The EventSource instantiation in use-sse-connect is leaking
the access token via URL query; remove the accessToken query parameter from the
EventSource URL and create the EventSource with credentials enabled so the
HttpOnly cookie is sent automatically (update the EventSource call in
use-sse-connect/index.ts where the EventSource is constructed to call the
subscribe endpoint without the token query and pass { withCredentials: true } as
the second argument).

---

Nitpick comments:
In `@src/hooks/use-sse/use-sse-connect/index.ts`:
- Around line 15-92: Replace all raw console.log/console.error calls in connect,
disconnect, reconnect, and setupSSEConnection with production-safe logging:
either remove the “[DEBUG]” messages or route them through the app’s structured
logger (e.g., logger.debug/info/error) and guard verbose debug logs behind an
environment check (NODE_ENV !== 'production' or a feature flag). Update uses
around eventSourceRef and retryRefreshRef (all console.* occurrences inside
connect, disconnect, reconnect, and setupSSEConnection) so no sensitive SSE
state is printed in production; ensure error paths still record enough context
via the structured logger.

In `@src/hooks/use-sse/use-sse-event/index.ts`:
- Around line 28-37: The useEffect uses queryClient (and SSE_INVALIDATION_MAP,
notificationKeys, data) but omits queryClient from its dependency array, causing
a react-hooks/exhaustive-deps lint warning; update the useEffect dependency
array to include queryClient (e.g., change [data] to [data, queryClient]) so the
effect declares all external references used inside (no other behavioral changes
required since QueryClient is stable in `@tanstack/react-query` v5).

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cab0f4 and 9747281.

📒 Files selected for processing (7)
  • src/app/providers.tsx
  • src/hooks/use-notification/use-notification-connect-sse/index.ts
  • src/hooks/use-sse/index.ts
  • src/hooks/use-sse/use-sse-connect/index.ts
  • src/hooks/use-sse/use-sse-event/index.ts
  • src/providers/provider-notification/index.tsx
  • src/types/service/notification.ts
💤 Files with no reviewable changes (1)
  • src/hooks/use-notification/use-notification-connect-sse/index.ts

Comment on lines +63 to +65
const es = new EventSource(
`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/v1/notifications/subscribe?accessToken=${token}`,
);
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 23, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

EventSource API custom headers support authentication best practices

💡 Result:

Does the browser EventSource API support custom headers?

No. The native browser EventSource(url, { withCredentials }) does not let you set arbitrary request headers like Authorization. This is a known/long-standing spec + implementation limitation. [1][2]

Authentication best practices for SSE when you can’t set headers

  1. Prefer cookie-based auth with HttpOnly session cookies (and use withCredentials: true when you need cookies on cross-origin SSE). This is the main thing native EventSource supports beyond the URL. [2][3]
  2. Avoid putting access tokens in the URL query string (/sse?token=...) because URLs get logged/cached and can leak via referrers/history. [4]
  3. If you use cookies, treat SSE like any other credentialed request:
    • Use TLS everywhere.
    • Lock down CORS (specific origins, Access-Control-Allow-Credentials: true only when needed).
    • Mitigate CSRF (e.g., SameSite cookies, CSRF tokens on state-changing endpoints; SSE itself is usually GET/read-only, but your overall session still matters).

If you need Authorization: Bearer ... (custom headers)

Use a fetch-based SSE client (recommended) or a polyfill:

  • Fetch-based SSE client (recommended): @microsoft/fetch-event-source (or equivalents) lets you send headers/body/method because it’s built on fetch(). [3]
  • Polyfill approach: event-source-polyfill/Yaffle’s EventSource polyfill supports custom headers via an init option. [5]

Token lifecycle best practice (important for long-lived streams)

Even with header-capable clients, plan for token expiry/refresh: long-lived connections + short-lived JWTs require a strategy (reconnect with a fresh token, or prefer session cookies). [2]

Sources: WHATWG html issue on headers [1], StackOverflow confirmation of native limitation + cookie suggestion [2], @microsoft/fetch-event-source README (custom headers via fetch) [3], discussion of URL token leakage risk [4], EventSource polyfill custom headers example [5].


🏁 Script executed:

# Check the implementation context
cat -n src/hooks/use-sse/use-sse-connect/index.ts | head -80

Repository: WeGo-Together/WeGo_FrontEnd

Length of output: 2780


EventSource 요청에서 accessToken을 URL 쿼리 파라미터로 전달하지 마세요.

토큰이 이미 HttpOnly 쿠키에 저장되어 있으므로, 다시 추출하여 URL에 노출하면 안 됩니다. 쿼리 파라미터로 전달된 토큰은 다음과 같이 유출될 수 있습니다:

  • 서버 액세스 로그에 기록
  • 브라우저 히스토리에 저장
  • Referer 헤더를 통해 제3자에게 유출

해결 방법: EventSource 생성 시 withCredentials: true 옵션을 추가하여 브라우저가 자동으로 쿠키를 전송하도록 변경하고, URL에서 accessToken 파라미터를 제거하세요.

const es = new EventSource(
  `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/v1/notifications/subscribe`,
  { withCredentials: true }
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/use-sse/use-sse-connect/index.ts` around lines 63 - 65, The
EventSource instantiation in use-sse-connect is leaking the access token via URL
query; remove the accessToken query parameter from the EventSource URL and
create the EventSource with credentials enabled so the HttpOnly cookie is sent
automatically (update the EventSource call in use-sse-connect/index.ts where the
EventSource is constructed to call the subscribe endpoint without the token
query and pass { withCredentials: true } as the second argument).

Copy link
Member Author

Choose a reason for hiding this comment

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

추후 백엔드 요청하여 수정진행하겠습니다. 이슈 생성 부탁드립니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

@Chiman2937, 네, 이슈를 생성해드리겠습니다.


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the SSE token security concern

gh issue create \
  --title "SSE 연결에서 accessToken URL 노출 보안 문제 해결" \
  --body "## 문제 설명

현재 SSE(Server-Sent Events) 연결 설정 시 accessToken을 URL 쿼리 파라미터로 전달하고 있습니다. 이는 다음과 같은 보안 위험을 초래합니다:

- 서버 액세스 로그에 토큰 기록
- 브라우저 히스토리에 토큰 저장
- Referer 헤더를 통한 제3자 유출 가능성

## 해결 방안

백엔드에서 EventSource 연결 시 HttpOnly 쿠키를 통한 인증을 지원하도록 수정이 필요합니다. 프론트엔드에서는 \`withCredentials: true\` 옵션을 사용하여 쿠키가 자동으로 전송되도록 설정할 수 있습니다.

## 관련 정보

- PR: https://github.com/WeGo-Together/WeGo_FrontEnd/pull/391
- 리뷰 코멘트: https://github.com/WeGo-Together/WeGo_FrontEnd/pull/391#discussion_r2840385123
- 요청자: `@Chiman2937`
- 파일: \`src/hooks/use-sse/use-sse-connect/index.ts\`" \
  --assignee "Chiman2937"

Length of output: 57


@Chiman2937, 이슈를 생성했습니다: #392

백엔드 수정 요청 후 진행하시면 됩니다. 감사합니다!

@Chiman2937 Chiman2937 changed the title Chiyoung refactor/notification [Refactor] 알림 SSE 훅 구조 개선 및 타입 단순화 Feb 23, 2026
@Chiman2937 Chiman2937 merged commit 8d82ad9 into main Feb 23, 2026
11 checks passed
@Chiman2937 Chiman2937 deleted the chiyoung-refactor/notification branch February 23, 2026 12:14
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.

1 participant