실시간 알림을 구현하려고
EventSource를 썼는데,
토큰 인증이 안 돼서401 Unauthorized에러가 나왔다고요?
이 포스팅에서 그 이유와 해결책을 아주 쉽게 설명해드립니다.
예를 들어, fetch나 axios는 요청을 보낼 때
우리가 직접 헤더를 설정할 수 있습니다.
fetch('/api/something', {
headers: {
Authorization: 'Bearer abc.def.ghi',
},
});
→ 이렇게 하면 브라우저가 우리가 설정한 Authorization 헤더를 그대로 전송합니다.
EventSource는 헤더를 설정할 수 없다const source = new EventSource('/api/subscribe');
→ EventSource는 우리가 헤더를 넣을 수 있는 방법이 없습니다.
→ 브라우저가 내부적으로 HTTP 요청을 자동 생성하고 관리하기 때문입니다.
즉, 토큰을 헤더에 넣고 싶어도 넣을 수가 없습니다.
| 이유 | 설명 |
|---|---|
| 보안 설계 상의 제한 | 브라우저가 기본적으로 안전하게 작동하도록 설계되어 있음 |
| SSE의 단순한 목적 | 서버 → 클라이언트 단방향 실시간 데이터 전송에 특화됨 |
| 자동 연결 유지 | EventSource는 끊어지면 브라우저가 자동으로 다시 연결 (헤더를 넣기 어려움) |
withCredentials: true로 설정const source = new EventSource('/api/subscribe', {
withCredentials: true,
});
✅ 가장 안전하고 정석적인 방식
const token = localStorage.getItem('accessToken');
const source = new EventSource(`/api/subscribe?token=${token}`);
@RequestParam token으로 인증⚠️ 테스트 용도로만 사용하고, 실서비스에서는 피해야 함
WebSocket은 연결할 때 커스텀 헤더를 넣을 수 있음| 항목 | 가능 여부 |
|---|---|
axios/fetch에서 Authorization 헤더 설정 | ✅ 가능 |
EventSource에서 Authorization 헤더 설정 | ❌ 불가능 |
EventSource에서 인증하려면 | ✅ 쿠키 or 쿼리 파라미터 필요 |
EventSource는 브라우저가 내부적으로 요청을 만들기 때문에, 우리가 헤더를 조작할 수 없고 Authorization 헤더를 넣을 수 없다.