title: "[GraphQL error]: Message: permission denied for function" using JWT in headers
body: <h2>The problem</h2>
  
  <p>Queries not requiring authorisation succeed, but a query requiring JWT authorisation fails.</p>
  
  <h2>Errors</h2>
  
  <p>In the browser console, I get the following error message:</p>
  
  <p><code>[GraphQL error]: Message: permission denied for function get_account_info, Location: [object Object], Path: getAccountInfo</code></p>
  
  <p>And this is the error I get in the server console:</p>
  
  <p><code>1 error(s) as guest in 101.18ms :: { getAccountInfo { username interface native customNative tutorial email __typename } }</code></p>
  
  <p>The fact that the error says <code>as guest</code> means that the role hasn't been set correctly (otherwise it would say <code>as loggedin</code>). I'm fairly sure this error isn't due to something on the SQL side, but rather in my JS code, but I've provided some SQL code below just in case.</p>
  
  <h2>The request</h2>
  
  <p>I installed GraphQL Developer Tools and saw that this is what was being sent in the request:</p>
  
  <p><strong>Request</strong></p>
  
  <ul>
  <li>Request URL: <a href="http://localhost:3000/graphql" rel="nofollow noreferrer">http://localhost:3000/graphql</a></li>
  <li>Method: POST</li>
  <li>HTTP version: HTTP/1.1</li>
  <li>Headers:
  
  <ul>
  <li>Origin: <a href="http://localhost:3000" rel="nofollow noreferrer">http://localhost:3000</a></li>
  <li>Accept-Encoding: gzip, deflate, br</li>
  <li>Host: localhost:3000</li>
  <li>Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6,lt;q=0.5,es;q=0.4</li>
  <li>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36</li>
  <li>content-type: application/json</li>
  <li>accept: <em>/</em></li>
  <li>Referer: <a href="http://localhost:3000/login" rel="nofollow noreferrer">http://localhost:3000/login</a></li>
  <li>Cookie: authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOjgsInN1YiI6InN0YXNAbXJzd29yZHNtaXRoLmNvbSIsImlzcyI6Imh0dHA6Ly9td3MtbWxhLmNvbSIsInBlcm1pc3Npb25zIjoxLCJpYXQiOjE1MjIwNzA4NzYsImV4cCI6MTUyMjY3NTY3Nn0.cXoy-SxSc5YVJ36lSmUoKAYU8KpZsZaFOS-xqcmbKPg</li>
  <li>Connection: keep-alive</li>
  <li>Content-Length: 179</li>
  <li>DNT: 1</li>
  </ul></li>
  </ul>
  
  <p>Note that <em>Cookie</em> has <em>authorization=[some token]</em>.
  <strong>Does this mean that there is no authorization header</strong> because it is living under <em>Cookie</em> for some reason? If so, <strong>how do I set the header correctly?</strong> Or is there anything else that I'm doing wrong?</p>
  
  <h2>The SQL code</h2>
  
  <p>I'm pretty sure that the SQL is fine, but here it is just in case.</p>
  
  <h3>JWT generation</h3>
  
  <pre><code>CREATE FUNCTION private.generate_jwt_for_user(username text)
      RETURNS json_web_token
      LANGUAGE plpgsql
      STABLE
      AS $$
          DECLARE
              n_moderator bigint;
          BEGIN
              SELECT count(*) INTO n_moderator
                 FROM private.moderator
                 WHERE account = username;
  
              IF n_moderator = 0
              THEN
                  RETURN ('loggedin', username)::json_web_token; -- x::Y means cast x to type Y
              ELSE
                  RETURN ('moderator', username)::json_web_token;
              END IF;
          END;
      $$;
  </code></pre>
  
  <h3>get_account_info</h3>
  
  <pre><code>CREATE FUNCTION public.get_account_info()
      RETURNS private.account_info
      LANGUAGE SQL
      SECURITY DEFINER
      STABLE
      AS $$
          SELECT *
          FROM private.account_info
          WHERE username = current_setting('jwt.claims.username')
      $$;
  </code></pre>
  
  <h2>The JavaScript code</h2>
  
  <h3>main.js</h3>
  
  <pre><code>// Meteor startup script. Runs reactRoutes, and puts the result in the 'content' div in index.html.
  
  import { Meteor } from 'meteor/meteor'
  import { render } from 'react-dom'
  import Routes from './routes'
  import React from 'react'
  import ApolloClient from 'apollo-boost'
  import { HttpLink } from 'apollo-link-http'
  import { ApolloLink, from } from 'apollo-link'
  import { ApolloProvider } from 'react-apollo'
  
  // Connect to the database using Apollo
  // Add middleware that adds a Json Web Token (JWT) to the request header
  
  const httpLink = new HttpLink({ uri: '/graphql' });
  
  const authMiddleware = new ApolloLink((operation, forward) =&gt; {
    // add the authorization to the headers
    const token = localStorage.getItem('token')
    operation.setContext(({ headers = {} }) =&gt; ({
      headers: {
        ...headers,
        authorization: 'Bearer ' + token || null,
      } 
    }));
  
    return forward(operation);
  })
  
  const client = new ApolloClient({
    link: from([
      authMiddleware,
      httpLink
    ]),
  });
  
  // &lt;ApolloProvider&gt; allows React to connect to Apollo
  // &lt;Routes&gt; allows client-side routing
  // The rendered page inserted into the HTML under 'content'
  Meteor.startup(() =&gt; {
      render(
          &lt;ApolloProvider client={client}&gt;
              &lt;Routes/&gt;
          &lt;/ApolloProvider&gt;,
          document.getElementById('content'))
  })
  </code></pre>
  
  <h3>app.js</h3>
  
  <p>Apologies for the long code with the occasional TODO comment, this is still a work in progress.</p>
  
  <pre><code>import React from 'react'
  import jwtDecode from 'jwt-decode'
  import { withApollo, graphql } from 'react-apollo'
  import gql from 'graphql-tag'
  import Nav from './auxiliary/nav'
  import Translate from 'react-translate-component'
  
  class UserAppBody extends React.Component {
      constructor(props) {
          super(props)
          this.state = {
              activeLanguageId: null
          }
      }
  
      setLanguage(langId) {
          this.setState({
              activeLanguageId: langId
          })
      }
  
      render() {
          let native = null
          let username = false
          // TODO: remove all userId references in app
          let tutorial = false
          if (this.props.accountInfo) {
              console.log("jwt: " + localStorage['token'])
              if (this.props.accountInfo.loading) { return &lt;Translate component="div" content="loading.loading" /&gt; }
              console.log(this.props.accountInfo)
              username = this.props.accountInfo.getAccountInfo.username
              tutorial = this.props.accountInfo.getAccountInfo.tutorial
              native =   this.props.accountInfo.getAccountInfo.native
          }
  
          return (
              &lt;div id="app-container"&gt;
                  &lt;Nav callbackLogOut={this.props.logOut} username={username} /&gt;
                  {/* Insert the children according to routes.jsx (this.props.children), along with the childrens' props.
                  username should come from query due to being wrapped by graphql for wrapped case; otherwise username is bool: false. */}
                  {React.cloneElement(
                      this.props.children, 
                      {
                          username: username,
                          hasSeenTutorial: tutorial,
                          native: native,
                          activeLanguageId: this.state.activeLanguageId, 
                          callbackLanguage: this.setLanguage.bind(this),
                          callbackUser: this.props.setUser,
                          callbackLogOut: this.props.logOut
                      }
                  )}
              &lt;/div&gt;
          )
      }
  }
  
  // UserAppBody will be wrapped in AppBody if user is logged in, this setup comes before the wrapping
  // Calling graphql on this turns it into a function which returns a React element (needed below)
  const accountInfoQuery = gql`query{
      getAccountInfo {
          username
          interface
          native
          customNative
          tutorial
          email
      }
  }`
  
  const accountInfoQueryConfig = {
      name: 'accountInfo'
  }
  const SignedInAppBody = graphql(accountInfoQuery, accountInfoQueryConfig)(UserAppBody)
  
  
  class AppBody extends React.Component {
      constructor(props) {
          super(props)
          const raw_jwt = localStorage.getItem('token')
          this.state = {
              isLoggedIn: !!raw_jwt // true if there is a jwt in local storage, false otherwise
          }
      }
  
      setUser(raw_jwt) {
          const jwt = jwtDecode(raw_jwt)
  
          // Check if the token has expired
          // Note that getTime() is in milliseconds, but jwt.exp is in seconds
          const timestamp = (new Date).getTime()
          if (!!jwt &amp;&amp; timestamp &lt; jwt.exp * 1000) {
              // If the token is still valid:
              // Store the token in memory, to be added to request headers
              localStorage.setItem('token', raw_jwt)
              // Set the state, to change the app
              this.setState({
                  isLoggedIn: true
              })
              // Automatically refresh the token
              this.refreshTimer = setInterval(this.refresh, 1000*60*20)  // Refresh every 20 minutes
              console.log('timer set up')
  
          } else {
              // If the token is no longer valid, log out to clear information
              this.logOut()
          }
      }
  
      logOut() {
          // Clear everything from setUser (state, memory, refreshing)
          localStorage.removeItem('refreshToken')
          localStorage.removeItem('token')
          clearInterval(this.refreshTimer)
          console.log('logging out')
          // second argument is a callback that setState will call when it is finished
          this.setState( { isLoggedIn: false }, this.props.client.resetStore() )
      }
  
      refresh() {
          // Get a new token using the refresh code
          this.props.refresh({variables: {input: {refreshToken: localStorage.getItem('refreshToken')}}})
          .then((response) =&gt; {
              // Store the new token
              const raw_jwt = response.data.refresh.jsonWebToken
              localStorage.setItem('token', raw_jwt)
          }).catch((error) =&gt; {
              // If we can't connect to the server, try again
              if (error.networkError) {
                  console.log('network error?') //TODO
                  //this.refresh()
              } else { //TODO
                  // If we connected to the server and refreshing failed, log out
                  console.log('error, logging out')
                  console.log(error)
                  this.logOut()
              }
          })
      }
  
      componentWillMount() {
          const raw_jwt = localStorage.getItem('token')
          if (!!raw_jwt) {
              console.log('found json web token, running setUser as App compenent mounts')
              this.setUser(raw_jwt)
              this.refresh()
          }
      }
  
      render() {
          let AppBodyClass
  
          if (this.state.isLoggedIn) {
              AppBodyClass = SignedInAppBody
          } else {
              AppBodyClass = UserAppBody
          }
          return &lt;AppBodyClass children={this.props.children} setUser={this.setUser.bind(this)} logOut={this.logOut.bind(this)} /&gt;
      }
  }
  
  const refresh = gql`mutation($input:RefreshInput!) {
      refresh(input:$input) {
          jsonWebToken
      }
  }`
  const refreshConfig = {
      name: 'refresh'
  }
  
  export default withApollo(graphql(refresh, refreshConfig)(AppBody))
  </code></pre>