Implementing Authentication
1. Passing Tokens in URL
Example: Query token
const ws = new WebSocket(`wss://api.example.com/ws?token=${encodeURIComponent(jwt)}`);
| Pros | Cons |
| Simple, works in browser | Logged in server access logs |
| No first-message dance | Cached in browser history |
Warning: Use short-lived tokens (≤ 60s) and rotate; never long-lived secrets in URLs.
| Context | Supported |
Browser WebSocket | No (only cookies / subprotocol) |
Node ws | Yes (headers option) |
| React Native | Partial |
Example: Subprotocol token (browser workaround)
const ws = new WebSocket("wss://x/", [`bearer.${jwt}`, "chat.v2"]);
// server reads Sec-WebSocket-Protocol and accepts
3. Sending Authentication Message
Example: Auth-first protocol
ws.addEventListener("open", () => ws.send(JSON.stringify({ "type":"auth","token":jwt })));
ws.addEventListener("message", (e) => {
const m = JSON.parse(e.data);
if (m.type === "auth.ok") onReady();
else if (m.type === "auth.fail") ws.close(4401, "auth");
});
| Step | Server Behavior |
| Accept connect | Allow unauthenticated open |
| Await auth | Timer (e.g. 5s) to close |
| Validate | Reply ok/fail |
| Promote | Mark connection authenticated |
4. Validating JWT Tokens
| Check | Detail |
| Signature | Verify with public key (RS/ES) or secret (HS) |
exp | Not expired (with clock skew) |
iss / aud | Match expected |
nbf | Not yet valid? |
| Revocation | Check denylist / use short TTL |
5. Using Cookie Authentication
Example: Same-origin cookie
// browser sends cookies on same-origin upgrades automatically
const ws = new WebSocket("wss://api.example.com/ws");
// server reads req.headers.cookie
| Attribute | Recommendation |
HttpOnly | Yes (prevent XSS theft) |
Secure | Yes (HTTPS/WSS only) |
SameSite | Lax or Strict |
| Cross-origin WS | Validate Origin header |
6. Implementing OAuth Flow
OAuth + WebSocket
- Frontend gets access token (Auth Code + PKCE)
- Request short-lived "WS ticket" from API
- Open WS with
?ticket=...
- Server validates ticket once, opens connection
- Refresh access token; rotate ticket on reconnect
7. Handling Session Management
| Concern | Action |
| Multi-device | Allow N sessions per user |
| Session bind | WS holds session ref |
| Revoke | Close all sockets on logout |
8. Implementing Token Refresh
Example: Refresh before expiry
function scheduleRefresh(exp) {
const skew = 30_000;
const delay = exp * 1000 - Date.now() - skew;
setTimeout(async () => {
const fresh = await refreshAccessToken();
ws.send(JSON.stringify({ "type":"auth.refresh","token":fresh.access }));
scheduleRefresh(fresh.exp);
}, Math.max(0, delay));
}
9. Closing Unauthorized Connections
| Code | Reason |
| 4401 | Auth required / token expired |
| 4403 | Forbidden (no permission) |
| 4408 | Auth timeout (no auth message) |
| 4429 | Auth rate-limited |
10. Implementing Multi-Factor Authentication
| Step | Detail |
| Primary auth | Password / OAuth before WS |
| MFA challenge | TOTP/WebAuthn over HTTP |
| Issue WS ticket | After MFA success |
| Step-up auth | Re-MFA before sensitive ops |