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() {