New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use Graphiql when /graphql protected by JWT token (authorization header) #59

Closed
sulliwane opened this Issue Nov 17, 2015 · 28 comments

Comments

Projects
None yet
@sulliwane
Copy link

sulliwane commented Nov 17, 2015

My /graphql route is protected by JWT token, so every HTTP request needs to set:

 headers: {
      Authorization: 'Bearer ' + token
    }

To get through the authentication middleware and hit /graphql.

How to manage this authentication step when using graphiql ? graphiql is so convenient, it's a pity to not use it :(
thanks for any suggestion!

@KyleAMathews

This comment has been minimized.

Copy link

KyleAMathews commented Nov 17, 2015

Download @skevy's https://github.com/skevy/graphiql-app and your header. I have the same setup as you and use this daily.

@sulliwane

This comment has been minimized.

Copy link
Author

sulliwane commented Nov 17, 2015

@KyleAMathews awesome, I will give it a shot (my main computer is linux distro though...). thanks

@skevy

This comment has been minimized.

Copy link
Contributor

skevy commented Nov 17, 2015

@sulliwane - I'm sure it would compile on Linux - just haven't tried.

@sulliwane

This comment has been minimized.

Copy link
Author

sulliwane commented Nov 17, 2015

I just tried npm install && npm start under linux (ubuntu 14.04) and graphiql-app-V0.3.1, but got blank screen, see here: skevy/graphiql-app#10

I close this issue as I have the answer now.

@sulliwane sulliwane closed this Nov 17, 2015

@cancan101

This comment has been minimized.

Copy link

cancan101 commented Dec 9, 2015

Any reason to close this issue and opposed to adding the header editor to the (main) graphiql?

@sulliwane

This comment has been minimized.

Copy link
Author

sulliwane commented Dec 9, 2015

No reason, indeed it would be nice if we could set the header directly into graphiql app. (I'm using graphiql-app right now.)

@sulliwane sulliwane reopened this Dec 9, 2015

@leebyron

This comment has been minimized.

Copy link
Contributor

leebyron commented Feb 3, 2016

GraphiQL is generic and doesn't know anything about the network! This is great because you can configure it to use whatever your GraphQL server uses. This is how @skevy was able to build a standalone app version of GraphiQL.

I suggest taking a look at the example - where you see graphQLFetcher is where you can configure your network fetching however you like, in your case by including any authentication details that may be necessary.

Often, when your GraphQL endpoint is behind a authorization feature like this, it is common to expose the GraphiQL tool via a different endpoint on your server.

@MarkAndrewJohnson

This comment has been minimized.

Copy link

MarkAndrewJohnson commented Mar 17, 2016

@leebyron I would agree being generic is a reason not to automate everything. I would think, though, that being generic is exactly why it DOES makes sense to have a field allowing custom headers to be set manually by the user!

I'm also unclear as to your last statement. It doesn't avoid the need for auth tokens to be pushed around.

@eugenehp

This comment has been minimized.

Copy link

eugenehp commented Jun 29, 2016

@MarkAndrewJohnson @sulliwane @cancan101 @KyleAMathews Guys, it would be interesting to get your opinion on this graphql/express-graphql#101

@mzohaibqc

This comment has been minimized.

Copy link

mzohaibqc commented Oct 19, 2016

I found a way to fix this problem. On Chrome, you can install an extention ModHeader https://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj which will allow you to modify request or response headers. In this way, you can send Authorization header with each request and graphiql will work fine.

@vitalcode

This comment has been minimized.

Copy link

vitalcode commented Dec 8, 2016

Look at auth-graphiql (https://github.com/vitalcode/auth-graphiql) that wraps GraphiQL providing support for bearer token and arbitrary URL. Great for testing GraphQL services secured with OAuth 2.0.

@jasonmorita

This comment has been minimized.

Copy link

jasonmorita commented Jan 9, 2017

For those still having this issue, my coworker came up with a cheap solution (in Express in my case). Have your GraphiQL answer at another endpoint as Lee said above and apply basic-auth to that, where you can supply your JWT, add it to the headers and then let express-jwt pick it up in the next middleware.

@hunt

This comment has been minimized.

Copy link

hunt commented Jan 29, 2017

Actually, I use a simple solution between our GraphQL development process. If you GraphQL server parse a access_token from querystring more than just a http header.

We can pass access_token in query string to the browser's address bar at our GraphiQL page ?access_token=xxx&query=... then GraphiQL will send access_token to req.query

I parse a token with something like express-bearer-token

@estaub

This comment has been minimized.

Copy link

estaub commented Jun 12, 2017

FWIW... In dev mode only, I've set up my server to save the most recent valid token used for the graphql endpoint, and slap it on any subsequent graphiql-driven queries (where the referer header is graphiql). I just sign into the app and then can use graphiql at will.

@sasso

This comment has been minimized.

Copy link

sasso commented Jul 7, 2017

Easy implementation to get JWT Token support in GraphiQL

https://gist.github.com/sasso/3c3d728e0049d5b66a2c19b349b7f164

screenshot 2017-07-07 09 46 20

@PetrSnobelt

This comment has been minimized.

Copy link

PetrSnobelt commented Jul 14, 2017

@sasso Thanks, but your old version does not support websockets :-(

@emjaksa

This comment has been minimized.

Copy link

emjaksa commented Sep 3, 2017

Hope this helps. How I implimented custom headers for my GraphiQL interface with a express-graphql server.

Modify your server to handle post requests from one endpoint and get requests to the graphiql interface on another.

app.post(
  '/graphql',
  expressGraphQL({
    schema: GraphQLSchema,
    graphiql: false, // Disable graphiql for posts requests
  }),
)

app.get(
  '/graphql',
  expressGraphQL({
    schema: GraphQLSchema,
    graphiql: true, // Enable graphiql for get requests
  }),
)

Basically you need to create a new index.html for your GraphiQL interface and add it to your servers public directory i.e. <public-path>/graphql/index.html. In that file you can modify the fetch function to send any additional headers in your requests. I got my index.html from the graphiql example.

I use webpack and the html-webpack-plugin to bundle the index.html. This allows it to get the correct version of graphql used in my project from the CDN. Below is an example of my webpack config and my ejs template of the index.html.

webpack.config.js

new HtmlWebpackPlugin({
  filename: 'graphql/index.html', // Write the file to <public-path>/graphql/index.html
  inject: false, // Do not inject any of your project assets into the template
  GRAPHQL_VERSION: packageJSON.dependencies.graphql.replace(/[^0-9.]/g, ''), // Get the graphql version from my package.json
  template: 'graphiql.ejs', // path to template
}),

graphiql.ejs

<!--
 *  Copyright (c) Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the license found in the
 *  LICENSE file in the root directory of this source tree.
-->
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        height: 100%;
        margin: 0;
        width: 100%;
        overflow: hidden;
      }
      #graphiql {
        height: 100vh;
      }
    </style>

    <!--
      This GraphiQL example depends on Promise and fetch, which are available in
      modern browsers, but can be "polyfilled" for older browsers.
      GraphiQL itself depends on React DOM.
      If you do not want to rely on a CDN, you can host these files locally or
      include them directly in your favored resource bunder.
    -->
    <script src="//cdn.jsdelivr.net/es6-promise/4.0.5/es6-promise.auto.min.js"></script>
    <script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
    <script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
    <script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>

    <link href="//cdn.jsdelivr.net/npm/graphiql@<%= htmlWebpackPlugin.options.GRAPHQL_VERSION %>/graphiql.css" rel="stylesheet" />
    <script src="//cdn.jsdelivr.net/npm/graphiql@<%= htmlWebpackPlugin.options.GRAPHQL_VERSION %>/graphiql.min.js"></script>
  </head>
  <body>
    <div id="graphiql">Loading...</div>
    <script>

      /**
       * This GraphiQL example illustrates how to use some of GraphiQL's props
       * in order to enable reading and updating the URL parameters, making
       * link sharing of queries a little bit easier.
       *
       * This is only one example of this kind of feature, GraphiQL exposes
       * various React params to enable interesting integrations.
       */

        // Parse the search string to get url parameters.
      var search = window.location.search;
      var parameters = {};
      search.substr(1).split('&').forEach(function (entry) {
        var eq = entry.indexOf('=');
        if (eq >= 0) {
          parameters[decodeURIComponent(entry.slice(0, eq))] =
            decodeURIComponent(entry.slice(eq + 1));
        }
      });

      // if variables was provided, try to format it.
      if (parameters.variables) {
        try {
          parameters.variables =
            JSON.stringify(JSON.parse(parameters.variables), null, 2);
        } catch (e) {
          // Do nothing, we want to display the invalid JSON as a string, rather
          // than present an error.
        }
      }

      // When the query and variables string is edited, update the URL bar so
      // that it can be easily shared
      function onEditQuery(newQuery) {
        parameters.query = newQuery;
        updateURL();
      }

      function onEditVariables(newVariables) {
        parameters.variables = newVariables;
        updateURL();
      }

      function onEditOperationName(newOperationName) {
        parameters.operationName = newOperationName;
        updateURL();
      }

      function updateURL() {
        var newSearch = '?' + Object.keys(parameters).filter(function (key) {
          return Boolean(parameters[key]);
        }).map(function (key) {
          return encodeURIComponent(key) + '=' +
            encodeURIComponent(parameters[key]);
        }).join('&');
        history.replaceState(null, null, newSearch);
      }

      // Defines a GraphQL fetcher using the fetch API. You're not required to
      // use fetch, and could instead implement graphQLFetcher however you like,
      // as long as it returns a Promise or Observable.
      function graphQLFetcher(graphQLParams) {
		// Get token from local storage
      	var token = localStorage.getItem('token')

        // This example expects a GraphQL server at the path /graphql.
        // Change this to point wherever you host your GraphQL server.
        return fetch('/graphql', {
          method: 'post',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': token ? 'Bearer '+ token : null,
          },
          body: JSON.stringify(graphQLParams),
          credentials: 'include',
        }).then(function (response) {
          return response.text();
        }).then(function (responseBody) {
          try {
            return JSON.parse(responseBody);
          } catch (error) {
            return responseBody;
          }
        });
      }

      // Render <GraphiQL /> into the body.
      // See the README in the top level of this module to learn more about
      // how you can customize GraphiQL by providing different values or
      // additional child elements.
      ReactDOM.render(
        React.createElement(GraphiQL, {
          fetcher: graphQLFetcher,
          query: parameters.query,
          variables: parameters.variables,
          operationName: parameters.operationName,
          onEditQuery: onEditQuery,
          onEditVariables: onEditVariables,
          onEditOperationName: onEditOperationName
        }),
        document.getElementById('graphiql')
      );
    </script>
  </body>
</html>
@wincent

This comment has been minimized.

Copy link
Contributor

wincent commented Sep 8, 2017

Thanks for sharing @emjaksa.

@gauravmakkar

This comment has been minimized.

Copy link

gauravmakkar commented Feb 8, 2018

@emjaksa Your code is working fine with query operations, what about subscriptions?...

@psamd

This comment has been minimized.

Copy link

psamd commented Feb 11, 2018

I use passport-http-bearer to parse token on my express server. It parses token from header as well as access_token from query string.

So I add the access_token in the GraphQL endpoint of GraphiQL. Here is my code.

app.get('/graphiql', graphiqlExpress({ endpointURL: '/graphql?access_token=<token>&' }));

This authenticates all requests made by GraphiQL

@pcattori pcattori referenced this issue Mar 28, 2018

Closed

Don't use Viewer #1

@AndreyMalykhin

This comment has been minimized.

Copy link

AndreyMalykhin commented Apr 3, 2018

I've ended up passing access token through Graphiql's Query Variables pane:

{ "accessToken": "azaza" }

@imolorhe

This comment has been minimized.

Copy link

imolorhe commented May 12, 2018

@AndreyMalykhin You can use https://altair.sirmuel.design/ also.

@greghaygood

This comment has been minimized.

Copy link

greghaygood commented Jun 8, 2018

@AndreyMalykhin +1 to Altair over the GraphiQL client if only for the ability to edit the headers when my tokens change (rather than deleting and re-entering them).

@nitrnitr

This comment has been minimized.

Copy link

nitrnitr commented Aug 8, 2018

What about

GraphiQL::Rails.config.headers['Authorization'] = -> (context) do
  "your jwt"
end

on the graphiql.rb initializer

@khaledosman

This comment has been minimized.

Copy link

khaledosman commented Sep 18, 2018

its really sad that this is still open after 3 years... All the solutions provided in the comments are just workarounds or reference to other tools. It shouldn't be too complicated to implement some form in the UI to add the headers.. Are there any intentions to implement this?

I'm currently using Insomnia which is like Postman for graphQL, but I'd rather just use graphiql.

@praveenweb

This comment has been minimized.

Copy link

praveenweb commented Oct 31, 2018

@khaledosman - We have a forked version of GraphiQL which adds a header UI. It comes with a configurable endpoint and headers and is hosted online at https://graphiql-online.com.

The source of the fork is here.

Hope its helpful for some people :)

@mkanand33

This comment has been minimized.

Copy link

mkanand33 commented Jan 14, 2019

I have a question about graphene authentication...how can I create different tokens for two different logins using graphene -jwt? I want to return a token for user login and also a token for manual admin login? how can I do both?

@yami12376

This comment has been minimized.

Copy link

yami12376 commented Jan 22, 2019

When there will be feature to add headers for tests by default in GraphiQL ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment