Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
Summary
After upgrading to Qlik Sense Enterprise on Windows (November 2024 and later, including November 2025 Patch 2), WebSocket connections to the Qlik Engine (QIX) that previously worked may start failing with “Handshake status 403 Forbidden”.
This mainly affects non-browser clients (Python, Java, .NET, etc.) that connect via a JWT virtual proxy.
This behavior is expected and caused by an extended security mechanism:
Cross-Site WebSocket Hijacking (CSWSH) prevention, which expands CSRF protection to WebSocket connections.
Typical symptoms
WebSocket handshake returns 403 Forbidden
JWT authentication succeeds
A Qlik session is created
A CSRF token is issued
The WebSocket connection is still rejected
Typical Proxy log message:
“Cross-Site Websocket Hijacking attack prevention check failed. Possible Cross-Site Websocket Hijacking attack (CSWSH) discovered.”
What changed
Starting with Qlik Sense November 2024+, WebSocket connections are subject to the same CSRF and Origin validation rules as HTTP requests.
Important consequences:
JWT alone is no longer sufficient for WebSocket authentication
JWT is used only to establish a session
The WebSocket connection must
reuse the same session
include a valid CSRF token
send an allowed Origin
NOT send an Authorization header
Common misconceptions
Adding the client IP to the host allow list (incorrect)
Sending “Authorization: Bearer <token>” in the WebSocket handshake
Reusing the Set-Cookie header as a Cookie header
Assuming CORS headers fix the issue for non-browser clients
Mixing short hostnames and FQDNs inconsistently
Required Virtual Proxy configuration
For the JWT virtual proxy, the Host allow list must contain the exact host names used by the client, for example:
host.example.local
Do not add client IP addresses.
The scheme (https) matters.
Additional response headers (CORS) are not required for service or script-based WebSocket clients.
Correct connection model (critical)
A two-phase approach is required.
Phase 1 – HTTP: establish session and CSRF
Use Authorization: Bearer <JWT> only here.
Call:
https://<host>/<virtual-proxy>/qps/csrftoken
Result:
CSRF token returned in the response header “qlik-csrf-token”
Session cookie (for example X-Qlik-Session-jwt)
Phase 2 – WebSocket: connect to QIX
Do NOT send an Authorization header.
Send only:
Session cookie
CSRF token
Origin header
Optionally, the CSRF token can also be sent as a query parameter.
Example (Python, simplified)
Use Bearer token only for the HTTP request to /qps/csrftoken
Extract qlik-csrf-token from the response header
Reuse the session cookie
Open the WebSocket without Authorization header
Send Cookie, CSRF token, and Origin
(Implementation details depend on the WebSocket library used.)
Important details
Origin
Must exactly match an entry in the virtual proxy host allow list
Scheme (https) is significant
Must be sent only once
CSRF token
Provided via response header (qlik-csrf-token)
Must match the active session
Session cookie is mandatory
Authorization header
Used only during HTTP session setup
Must not be sent during the WebSocket handshake
WebSocket subprotocol
Do not force “qlik.api”
If the server does not echo it back, forcing it causes client-side errors
Success indicator
A successful WebSocket handshake returns:
HTTP/1.1 101 Switching Protocols
After this, normal QIX JSON-RPC communication (OpenDoc, GetDocList, etc.) works as expected.
Conclusion
The 403 error after upgrading is not a bug, but the result of intentional security hardening.
JWT creates the session — the session authenticates the WebSocket.
Once non-browser clients follow the session + CSRF + Origin model, WebSocket connections work reliably again.
I think you are need update topic and change affected QlikSense to Nov 2024+. Not 2025+
Anyway. Could the same issue occur when using the browser client to access the Qlik Sense server on the company's private network via a VPN connection?