Skip to content

EventSource authentication headers ​

EventSource auth headers

Problem: new EventSource('/orders/stream') cannot set Authorization. Headers are ignored. Browsers refuse custom headers on EventSource.

Solution: Stream over native fetch with tanstack-fetch/sse, attach headers normally, and refresh tokens on 401 before reconnecting.

Why EventSource fails auth ​

ts
// Cannot set Authorization — browsers ignore it
const es = new EventSource('https://api.example.com/orders/stream', {
  headers: { Authorization: `Bearer ${token}` }, // ❌ not applied
})

tanstack-fetch/sse (fetch-based stream) ​

ts
import { createFetch } from 'tanstack-fetch/sse'

const api = createFetch({
  baseUrl: import.meta.env.VITE_API_URL,
  getToken: () => localStorage.getItem('access_token'),
})

const stream = api.sse<OrderEvent>('/orders/stream', {
  headers: {
    Authorization: `Bearer ${api.getToken() ?? ''}`,
  },
  onMessage: (data) => console.log(data),
})

Headers set here are real HTTP headers — Authorization works.

Reconnect with Last-Event-ID ​

Use sse-resume for Last-Event-ID resume after disconnect:

ts
plugins: ['sse-resume'],

See /recipes/sse-resume.

Auth on reconnect ​

Read token again before reconnect so a refreshed token is sent:

ts
api.sse('/orders/stream', {
  headers: {
    Authorization: `Bearer ${localStorage.getItem('access_token') ?? ''}`,
  },
})

WebSocket has the same problem ​

Browser WebSocket can't send Authorization either. api.ws from tanstack-fetch/live makes the choice explicit (authIn: 'query' | 'protocol'), sends a real header on Node 22+ / Bun / Deno, and refetches the token on every reconnect. See WebSocket guide · Auth.

MIT Licensed · Created by Mohammad Garmabi · Not an official TanStack package