This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch fix/graphql-websocket-auth
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/fix/graphql-websocket-auth by 
this push:
     new 5ef9ce208 Read the playground's WebSocket credential from the live 
headers editor
5ef9ce208 is described below

commit 5ef9ce20815f7c21e105c6bb3ad22f20f25862f6
Author: Serge Huber <[email protected]>
AuthorDate: Thu Sep 3 13:41:47 2026 +0200

    Read the playground's WebSocket credential from the live headers editor
    
    The previous commit read the Authorization from the "graphiql:headers" local
    storage entry, but GraphiQL only writes that entry when 
shouldPersistHeaders is
    enabled, and it defaults to false, so the credential was never found and a
    subscription stayed unauthenticated.
    
    Take the value from the headers GraphiQL passes to the fetcher on every 
request
    instead, which is the live content of the Headers tab. This keeps a single
    credential entry point for both transports and, unlike enabling header
    persistence, keeps the credential in memory rather than writing it to 
browser
    storage.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../src/main/resources/assets/js/index.jsx         | 33 +++++++++++-----------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/graphql/graphql-ui/src/main/resources/assets/js/index.jsx 
b/graphql/graphql-ui/src/main/resources/assets/js/index.jsx
index 013ea5ec4..a1de4467e 100644
--- a/graphql/graphql-ui/src/main/resources/assets/js/index.jsx
+++ b/graphql/graphql-ui/src/main/resources/assets/js/index.jsx
@@ -34,35 +34,36 @@ function graphqlWsUrl() {
 }
 
 // The browser WebSocket API cannot set request headers on the handshake, so 
the server authenticates a
-// subscription from the connection_init payload instead. Reuse the 
Authorization the operator already
-// enters in GraphiQL's "Headers" tab (the same credential used for HTTP admin 
queries) so HTTP and
-// WebSocket authenticate identically. GraphiQL persists that editor to 
localStorage.
-function authorizationFromHeadersEditor() {
-    try {
-        const stored = window.localStorage.getItem('graphiql:headers');
-        if (!stored) {
-            return null;
-        }
-        const headers = JSON.parse(stored);
-        const key = Object.keys(headers).find((name) => name.toLowerCase() === 
'authorization');
-        return key && headers[key] ? headers[key] : null;
-    } catch (e) {
+// subscription from the connection_init payload instead. GraphiQL hands the 
live "Headers" tab content
+// to the fetcher on every request, so capture it here and reuse its 
Authorization as the WebSocket
+// connection parameters: HTTP and WebSocket then use the same credential, and 
nothing is persisted.
+let latestHeaders = null;
+
+function authorizationHeader() {
+    if (!latestHeaders) {
         return null;
     }
+    const key = Object.keys(latestHeaders).find((name) => name.toLowerCase() 
=== 'authorization');
+    return key && latestHeaders[key] ? latestHeaders[key] : null;
 }
 
 function createFetcher() {
-    return createGraphiQLFetcher({
+    const fetcher = createGraphiQLFetcher({
         url: graphqlHttpUrl(),
         wsClient: createClient({
             url: graphqlWsUrl(),
-            // Evaluated on each (re)connect; sent as the connection_init 
payload.
+            // Evaluated on each (re)connect, and sent as the connection_init 
payload.
             connectionParams: () => {
-                const authorization = authorizationFromHeadersEditor();
+                const authorization = authorizationHeader();
                 return authorization ? { Authorization: authorization } : {};
             },
         }),
     });
+
+    return (graphQLParams, opts) => {
+        latestHeaders = (opts && opts.headers) || null;
+        return fetcher(graphQLParams, opts);
+    };
 }
 
 function QueryPlayground() {

Reply via email to