C.W.K.
Stream
Lesson 07 of 08 · published

The WebSocket Handshake

~13 min · foundations, rfc-6455, handshake

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

From HTTP/1.1 to WebSocket

Behind the magic, the WebSocket handshake is just an HTTP/1.1 GET with four critical headers: Upgrade: websocket, Connection: Upgrade, Sec-WebSocket-Key, and Sec-WebSocket-Version: 13. The server's job is to recognize them, compute a derived value, and respond with 101 Switching Protocols.

The Sec-WebSocket-Accept hash

The client sends a base64-encoded random nonce in Sec-WebSocket-Key. The server concatenates that with a fixed magic GUID (258EAFA5-E914-47DA-95CA-C5AB0DC85B11), takes the SHA-1, and returns the base64 of that hash in Sec-WebSocket-Accept. This proves the server actually understands the WebSocket protocol — a generic HTTP server cannot accidentally complete the handshake.

Optional handshake headers

Sec-WebSocket-Protocol negotiates a subprotocol like graphql-ws or mqtt. Sec-WebSocket-Extensions negotiates extensions, most commonly permessage-deflate for compression. Origin identifies the calling page — your server should validate it.

Code

Computing Sec-WebSocket-Accept by hand·python
import hashlib, base64

GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

def server_accept(client_key: str) -> str:
    raw = (client_key + GUID).encode('ascii')
    digest = hashlib.sha1(raw).digest()
    return base64.b64encode(digest).decode('ascii')

# From RFC 6455
print(server_accept('dGhlIHNhbXBsZSBub25jZQ=='))
# -> 's3pPLMBiTxaQ9kYGzzhZRbK+xOo='
Validate Origin before accepting·python
ALLOWED = {'https://app.example.com', 'https://admin.example.com'}

@app.websocket('/ws')
async def ws_endpoint(websocket: WebSocket):
    origin = websocket.headers.get('origin', '')
    if origin not in ALLOWED:
        # Reject during handshake — never .accept()
        await websocket.close(code=4003, reason='forbidden origin')
        return
    await websocket.accept()
    # ...

External links

Exercise

Run the server_accept function above against three random base64 client keys. Then capture a real WebSocket handshake in your browser's network panel (any chat-style site works). Verify by hand that the server's Sec-WebSocket-Accept matches what your function computes from the request's Sec-WebSocket-Key.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.