{
  "slug": "Understanding-Server-Sent-Events--SSE---Architecture--Authentication--and-Testing-in-NestJS-oc5uf",
  "title": "Understanding Server-Sent Events (SSE): Architecture, Authentication, and Testing in NestJS",
  "subtitle": "",
  "excerpt": "Introduction Modern web applications often need real-time communication. Examples include: Notifications Chat applications Live dashboards Stock prices Progress tracking Monitoring systems Most developers immediately th…",
  "date": "2026-06-26",
  "tags": [
    "API",
    "Testing"
  ],
  "readingTime": "2 min",
  "url": "https://www.linkedin.com/pulse/understanding-server-sent-events-sse-architecture-nestjs-shaterian-oc5uf",
  "hero": "https://media.licdn.com/dms/image/v2/D4D12AQH-nTiTjQs2DQ/article-cover_image-shrink_720_1280/B4DZ8EZ9VUHEAQ-/0/1782485347673?e=2147483647&v=beta&t=iDOOT7BiSsuIQi-N_xhuyktTC3g7_rE2maa0_55MZA4",
  "content": [
    {
      "type": "heading",
      "level": 3,
      "text": "Introduction"
    },
    {
      "type": "paragraph",
      "html": "Modern web applications often need real-time communication. Examples include:<!---->"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Notifications<!---->",
        "Chat applications<!---->",
        "Live dashboards<!---->",
        "Stock prices<!---->",
        "Progress tracking<!---->",
        "Monitoring systems<!---->"
      ]
    },
    {
      "type": "paragraph",
      "html": "Most developers immediately think about WebSockets, but another technology is simpler and often sufficient:<!---->"
    },
    {
      "type": "paragraph",
      "html": "<strong>Server-Sent Events (SSE).</strong><!---->"
    },
    {
      "type": "paragraph",
      "html": "This article explains:<!---->"
    },
    {
      "type": "list",
      "ordered": true,
      "items": [
        "What SSE is<!---->",
        "How it works internally<!---->",
        "When to use it<!---->",
        "How to implement it in NestJS<!---->",
        "Common pitfalls<!---->",
        "Authentication challenges<!---->",
        "How to test SSE endpoints in Node.js and Vitest<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "What is Server-Sent Events (SSE)?"
    },
    {
      "type": "paragraph",
      "html": "Server-Sent Events is an HTTP-based technology that allows a server to continuously push events to a client over a single long-lived HTTP connection.<!---->"
    },
    {
      "type": "paragraph",
      "html": "Unlike a normal HTTP request:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Client ---> Request\nServer ---> Response\nConnection Closed"
    },
    {
      "type": "paragraph",
      "html": "SSE keeps the connection open:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Client ---> Request\nServer ---> Event 1\nServer ---> Event 2\nServer ---> Event 3\nConnection remains open"
    },
    {
      "type": "paragraph",
      "html": "The client passively listens for events.<!---->"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE is One-Way Communication"
    },
    {
      "type": "paragraph",
      "html": "SSE only allows:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Server ---> Client"
    },
    {
      "type": "paragraph",
      "html": "It does <strong>not</strong> support:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Client ---> Server"
    },
    {
      "type": "paragraph",
      "html": "If bidirectional communication is required, WebSockets are usually a better choice.<!---->"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE vs Polling"
    },
    {
      "type": "heading",
      "level": 3,
      "text": "Polling"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Every 5 seconds:\n\nClient ---> GET /notifications\nServer ---> []"
    },
    {
      "type": "paragraph",
      "html": "Problems:<!---->"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Wasted requests<!---->",
        "Increased server load<!---->",
        "Delayed updates<!---->",
        "Poor scalability<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 3,
      "text": "SSE"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "Client ---> GET /notifications/subscribe\nServer ---> Keep connection open\n\nServer ---> Notification 1\nServer ---> Notification 2\nServer ---> Notification 3"
    },
    {
      "type": "paragraph",
      "html": "Advantages:<!---->"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Near real-time<!---->",
        "Less overhead<!---->",
        "Simpler than WebSockets<!---->",
        "Uses plain HTTP<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE Message Format"
    },
    {
      "type": "paragraph",
      "html": "SSE uses plain text.<!---->"
    },
    {
      "type": "paragraph",
      "html": "Example:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "data: Hello World"
    },
    {
      "type": "paragraph",
      "html": "JSON payload:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "data: {\"id\":1,\"title\":\"New Message\"}"
    },
    {
      "type": "paragraph",
      "html": "Named event:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "event: notification\ndata: {\"id\":1}"
    },
    {
      "type": "paragraph",
      "html": "Message with ID:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "id: 123\ndata: {\"id\":1}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Browser API"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "const es = new EventSource('/notifications/subscribe');\n\nes.onmessage = (event) => {\n  const data = JSON.parse(event.data);\n  console.log(data);\n};"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE in NestJS"
    },
    {
      "type": "paragraph",
      "html": "NestJS has first-class support for SSE.<!---->"
    },
    {
      "type": "paragraph",
      "html": "Controller:<!---->"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Sse('subscribe')\nsse() {\n  return interval(1000).pipe(\n    map(i => ({\n      data: { count: i },\n    })),\n  );\n}"
    },
    {
      "type": "paragraph",
      "html": "Client receives:<!---->"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Recommended by LinkedIn"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "data: {\"count\":1}\n\ndata: {\"count\":2}\n\ndata: {\"count\":3}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Real Example: Notification Service"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Sse('subscribe')\nsse(\n  @User() user: RequestUser,\n) {\n  return this.inAppService.listen(user.id);\n}"
    },
    {
      "type": "paragraph",
      "html": "Service:<!---->"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "listen(userId: string): Observable<MessageEvent> {\n  return this.subject.asObservable();\n}"
    },
    {
      "type": "paragraph",
      "html": "When a notification is created:<!---->"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "this.subject.next({\n  data: notification,\n});"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Authentication with SSE"
    },
    {
      "type": "paragraph",
      "html": "SSE endpoints are often protected.<!---->"
    },
    {
      "type": "paragraph",
      "html": "Example:<!---->"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@UseGuards(SessionGuard)\n@Sse('subscribe')"
    },
    {
      "type": "paragraph",
      "html": "This works perfectly in browsers because cookies are automatically sent.<!---->"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "The Testing Problem"
    },
    {
      "type": "paragraph",
      "html": "During end-to-end testing, we encountered:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "401 Unauthorized"
    },
    {
      "type": "paragraph",
      "html": "even though authentication worked for normal requests.<!---->"
    },
    {
      "type": "paragraph",
      "html": "The SSE request looked like this:<!---->"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "new EventSource(url, {\n  headers: {\n    Cookie: cookie,\n  },\n});"
    },
    {
      "type": "paragraph",
      "html": "The problem was:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "eventsource@4"
    },
    {
      "type": "paragraph",
      "html": "does not support custom headers anymore.<!---->"
    },
    {
      "type": "paragraph",
      "html": "The Cookie header was silently ignored.<!---->"
    },
    {
      "type": "paragraph",
      "html": "The actual request became:<!---->"
    },
    {
      "type": "code",
      "lang": "http",
      "code": "GET /notifications/in-app/subscribe\nAccept: text/event-stream"
    },
    {
      "type": "paragraph",
      "html": "without:<!---->"
    },
    {
      "type": "code",
      "lang": "http",
      "code": "Cookie: auth_session=..."
    },
    {
      "type": "paragraph",
      "html": "The server returned:<!---->"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "401 Unauthorized"
    },
    {
      "type": "hr"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Solution: Use Fetch Instead of EventSource"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "const response = await fetch(url, {\n  headers: {\n    Cookie: cookie,\n    Accept: 'text/event-stream',\n  },\n});"
    },
    {
      "type": "paragraph",
      "html": "This allows cookies to be sent properly.<!---->"
    },
    {
      "type": "paragraph",
      "html": "The response stream can then be parsed manually.<!---->"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "When Should You Use SSE?"
    },
    {
      "type": "paragraph",
      "html": "SSE is excellent for:<!---->"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Notifications<!---->",
        "Progress tracking<!---->",
        "Monitoring dashboards<!---->",
        "Stock prices<!---->",
        "Live metrics<!---->",
        "Log streaming<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "When Should You Use WebSockets Instead?"
    },
    {
      "type": "paragraph",
      "html": "Use WebSockets when:<!---->"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Bidirectional communication is required<!---->",
        "Chat applications<!---->",
        "Multiplayer games<!---->",
        "Collaborative editing<!---->",
        "Frequent client-to-server messages<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE Advantages"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "Simple HTTP protocol<!---->",
        "Automatic reconnection<!---->",
        "Lightweight<!---->",
        "Firewall friendly<!---->",
        "Easy to scale<!---->",
        "Native browser support<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "SSE Limitations"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "One-way communication<!---->",
        "Text-only protocol<!---->",
        "Browser connection limits<!---->",
        "Less flexible than WebSockets<!---->"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Final Thoughts"
    },
    {
      "type": "paragraph",
      "html": "Server-Sent Events are one of the most underused features of modern web development. For many real-time applications, especially notifications and dashboards, SSE provides a simpler, more scalable, and easier-to-maintain alternative to WebSockets.<!---->"
    },
    {
      "type": "paragraph",
      "html": "Understanding the protocol, its authentication model, and its testing challenges can save hours of debugging and lead to significantly cleaner real-time architectures.<!---->"
    }
  ]
}
