From 89d5b7e9df76418f3858321b85a6bb3c84193e79 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 18 Aug 2023 20:51:26 +0200 Subject: [PATCH] Support CSRF protection in GraphiQL with cookie-to-header strategy Prior to this commit, secured applications with CSRF protection could not easily use the GraphiQL integration shipped with Spring for GraphQL, as the JavaScript code would not work with any CSRF protection strategy for single page apps. This commit checks whether the main HTTP response contains a `XSRF-TOKEN` Cookie value, and uses it as a `X-XSRF-TOKEN` request header for the next AJAX request to the `/graphql` endpoint. Note that a specific configuration must be set in Spring Security to achieve that: * the CSRF token must be sent as a response Cookie for the initial authenticated request * if the application is protected against BREACH, all new token values must be sent as response cookies as well and a request handler must be configured Closes gh-758 --- spring-graphql/src/main/resources/graphiql/index.html | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spring-graphql/src/main/resources/graphiql/index.html b/spring-graphql/src/main/resources/graphiql/index.html index 9c1e6dab..7daaf658 100644 --- a/spring-graphql/src/main/resources/graphiql/index.html +++ b/spring-graphql/src/main/resources/graphiql/index.html @@ -30,19 +30,17 @@ const wsPath = params.get("wsPath") || "/graphql"; const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const subscriptionUrl = `${wsProtocol}//${location.host}${wsPath}`; - - const gqlFetcher = GraphiQL.createFetcher({ - url, - subscriptionUrl, - }); - + const gqlFetcher = GraphiQL.createFetcher({'url': url, 'subscriptionUrl': subscriptionUrl}); const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin(); + const xsrfToken = document.cookie.match(new RegExp('(?:^| )XSRF-TOKEN=([^;]+)')); + const headers = xsrfToken ? `{ "X-XSRF-TOKEN" : "${ xsrfToken[1] }" }` : `{}`; ReactDOM.render( React.createElement(GraphiQL, { fetcher: gqlFetcher, defaultVariableEditorOpen: true, headerEditorEnabled: true, shouldPersistHeaders: true, + headers: headers, plugins: [explorerPlugin] }), document.getElementById('graphiql'),