What is the Sec-WebSocket-Key header?
The Sec-WebSocket-Key request header is part of the WebSocket opening handshake defined in RFC 6455. The client MUST send it, and its value MUST be a randomly selected 16-byte value, base64-encoded, chosen fresh for each connection. That always produces a 24-character string ending in ==.
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==The server does not decode it. It appends the fixed GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 to the key exactly as received, takes the SHA-1 hash, base64-encodes it, and returns the result in Sec-WebSocket-Accept on its 101 Switching Protocols response.
The point, in RFC 6455’s words, is to prove the server received a WebSocket handshake, so a WebSocket server cannot be tricked into accepting a connection from something that is not a WebSocket client, such as a crafted form submission or XMLHttpRequest. The header MUST NOT appear more than once in a request.
API Usage & Best Practices
- It is not authentication and not a secret. Anyone can generate a key and compute the matching accept value. Authenticate the handshake request with its credentials and authorize the connection on the server, as you would any other request.
- Check
Originyourself. Browsers do not apply CORS to WebSocket connections, so a page on any site can open one to your API and the browser will attach your cookies. Validate theOriginheader in the handshake against an allowlist, or do not use cookie authentication for WebSockets. - Browsers set it, scripts cannot. Header names starting with
Sec-are forbidden request headers in the Fetch standard, so page JavaScript cannot set or forge this header. That is the reason for the prefix. - Let your library generate it. If you implement a client, the nonce must be random per connection. Reusing a fixed key is a protocol violation, even if many servers will accept it.
- Reject a malformed key. A key that does not decode to 16 bytes, or a handshake with more than one key, is not a valid WebSocket handshake. Answer with
400 Bad Requestrather than upgrading. - It does not exist over HTTP/2 or HTTP/3. RFC 8441 bootstraps WebSockets over HTTP/2 with an extended
CONNECTrequest and says implementations do not processSec-WebSocket-KeyandSec-WebSocket-Acceptthere, because the:protocolpseudo-header supersedes them. RFC 9220 uses the same mechanism for HTTP/3. SeeUpgrade.
Examples
The client side of the opening handshake from RFC 6455:
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==Origin: http://example.comSec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13The server’s acceptance, with the accept value derived from that key:
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=Sec-WebSocket-Protocol: chat