Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungI wanted the diff, not a screenshot: a small URL-change API(24.09.2026 um 06:05 Uhr)
Sichere ProgrammierungFreeze Object Identity Before One Mutator Extract(24.09.2026 um 06:06 Uhr)
Sichere ProgrammierungRun an n8n workflow when a page's text changes(24.09.2026 um 06:12 Uhr)
Sichere ProgrammierungThe Spreadsheet That Runs Your Company (And Why That Should Worry You)(24.09.2026 um 06:12 Uhr)
Sichere ProgrammierungArchitecting an Enterprise Network on AWS Cloud WAN(24.09.2026 um 06:31 Uhr)
Sichere ProgrammierungI wanted the diff, not a screenshot: a small URL-change API(24.09.2026 um 06:05 Uhr)
Sichere ProgrammierungFreeze Object Identity Before One Mutator Extract(24.09.2026 um 06:06 Uhr)
Sichere ProgrammierungRun an n8n workflow when a page's text changes(24.09.2026 um 06:12 Uhr)
Sichere ProgrammierungThe Spreadsheet That Runs Your Company (And Why That Should Worry You)(24.09.2026 um 06:12 Uhr)
Sichere ProgrammierungArchitecting an Enterprise Network on AWS Cloud WAN(24.09.2026 um 06:31 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

The WebSocket Auth Problem: Cookies vs. Bearer Tokens

If you've ever built a real-time web app using WebSockets, you've probably hit this exact wall - how do I do the auth. On the HTTP side, the answer is pretty simple. You either use a cookie, which has so many npm packages, or you attach…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

If you've ever built a real-time web app using WebSockets, you've probably hit this exact wall - how do I do the auth.



On the HTTP side, the answer is pretty simple. You either use a cookie, which has so many npm packages, or you attach an Authorization: Bearer <token> header to your requests, which is a simple JWT signed string. However, things get a bit weird on the WebSocket side of things.



The fundamental issue stems from how WebSocket connections are established. Before a WebSocket connection becomes a continuous bidirectional channel of data, it starts off as a simple HTTP GET request with an Upgrade header. This is known as the WebSocket Handshake.



Let's dive into why this handshake makes the seemingly simple task of authentication a surprisingly nuanced architectural decision.









Why Bearer Tokens are Clunky for WebSockets



If your application relies on Bearer tokens (usually stored in memory or local storage on the client side), you are used to attaching them via the Authorization header using an interceptor or a fetch wrapper.




// A typical HTTP request with a Bearer token
fetch('/api/data', {
headers: {
'Authorization': `Bearer ${myToken}`
}
});






However, the native browser WebSocket API does not support custom headers.




// This is all we get.
const ws = new WebSocket('wss://api.myapp.com/socket');






Since you can't pass the token in an Authorization header during the initial HTTP Upgrade request, developers are forced into clunky workarounds:





  1. Query Parameters: Passing the token in the URL (wss://api.myapp.com/socket?token=ey...). This is generally considered a bad practice because URLs (and the sensitive tokens within them) end up in server logs, browser histories, and proxy logs.


  2. First Message Auth: Opening the WebSocket connection unauthenticated, and then requiring the client to immediately send an authentication message containing the token before the server accepts any further messages. While secure, this adds latency and complexity to the connection lifecycle logic. You have to write boilerplate to handle connections that open but never authenticate.


  3. Subprotocols: A hacky but working method where the token is passed as a WebSocket subprotocol (new WebSocket('wss://...', ['access_token', token])).



None of these feel particularly clean or idiomatic.









Why Cookies Work Naturally



This brings us to cookies, the method that I chose for Relay! Cookies are managed by the browser. Whenever the browser makes an HTTP request to a domain, it automatically attaches the cookies associated with that domain.



Because the WebSocket handshake is just a standard HTTP GET request, the browser automatically includes your cookies in the first request itself!



If your authentication system sets an HTTP-only cookie containing your JWT or session ID when the user logs in, you literally don't have to change any client-side code to authenticate your WebSockets. The browser handles it natively and securely.




// The browser automatically attaches the JWT auth cookie!
const ws = new WebSocket('wss://api.myapp.com/socket');











While the client side becomes trivial, the backend need manual cookie parsing. When your WebSocket server receives the upgrade request, it hands you a raw Node.js IncomingMessage object.



Unlike Express requests which come with the cookies objects provided by middleware, the IncomingMessage just gives you the raw cookie header string. You have to parse it yourself before accepting the WebSocket connection.



Below is how I did the cookie parsing in Relay!






1. Extracting and Verifying the Token



First, we need a utility function to take the raw IncomingMessage, parse the cookie string, and verify our JWT.




import cookie from "cookie";
import jwt from "jsonwebtoken";
import type { IncomingMessage } from "http";
import { jwtPayloadSchema } from "../../http/schemas/auth.schema.js";

// Extract user ID from the raw HTTP upgrade request
export function extractUserId(req: IncomingMessage): string | null {
// Parse the raw cookie header string
const cookies = cookie.parse(req.headers.cookie ?? "");
const token = cookies.token;

if (!token) return null;

try {
// Verify the JWT signature
const decoded = jwt.verify(token, process.env.JWT_SECRET as string);

// Validate the payload shape
const parsed = jwtPayloadSchema.safeParse(decoded);
if (!parsed.success) {
return null;
}

// Return the authenticated User ID
return parsed.data.id;
} catch {
return null; // Token is invalid or expired
}
}









2. The main Socket handling code



Now here, I integrate this utility into my WebSocket server initialisation. I intercept the connection, attempt to extract the user ID, and immediately close the connection with a 4001 Unauthorized status if the authentication fails.




import { WebSocketServer, type WebSocket } from "ws";
import type { Server as HttpServer } from "http";
import { extractUserId } from "./handlers/message.handler.js";
import { sockets } from "./store.js";

export function initWebSocketServer(server: HttpServer) {
const wss = new WebSocketServer({ server });

wss.on("connection", (ws: WebSocket, request: IncomingMessage) => {
ws.on("error", console.error);

// 1. Authenticate immediately using the parsed cookie
const id = extractUserId(request);

// 2. Reject unauthenticated connections at the handshake level
if (!id) {
ws.close(4001, "Unauthorized");
return;
}

// 3. Connection is fully authenticated!
// We can safely associate this socket with the user
sockets.addUser(id, ws);

// Proceed with authorized application logic...
console.log(`User ${id} connected successfully.`);

ws.on("message", async (data) => {
// ... handle incoming messages knowing the sender's true identity
});

ws.on("close", () => {
sockets.removeUserSocket(id, ws);
});
});
}









Wrapping up



When building real-time applications, relying on HTTP-only cookies for authentication eliminates the friction of securing WebSockets. By leaning on the browser's native cookie management, we avoid leaking tokens in URLs and bypass the complexity of first-message authentication handshakes. It requires a tiny bit of manual header parsing on the backend, but the resulting client-side simplicity and security posture are well worth the trade-off.



For those of you who would like to go through the codebase, you can do so here.

I'll be back with more next week. Until then, stay consistent!

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - The WebSocket Auth Problem: Cookies vs. Bearer Tokens
id: 46c4742e-11a5-4c77-a3aa-973a5f8f6803
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "The WebSocket Auth Problem: Co" ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich The WebSocket Auth Problem: Cookies vs. .... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten The WebSocket Auth Problem: Cookies vs. Bearer Tokens

Thematisch verwandte Begriffe: WebSocket, Auth, Problem, Cookies · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96676 | A vulnerability was identified in Fast FAC1900R 20190827_2.0.2. The impa…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick