How do I pass the authenticated user's idToken when making a gql request?

I’m probably missing something basic, but I’m trying to understand how to send a GraphQL request to the 8base database that’s authenticated with the logged-in user’s idToken.

I’m using 8base’s auth, modeled after the 8base React Starter App.

I’m trying to use client from the @8base/api-client npm module, the same way that it is used in /routes/auth/callback.js in the starter app:

const gqlResponse = await client.request(gql.USER_UPDATE_STRIPE_ID_MUTATION, {
  state,
  stripe_code
})

When I inspect the network request to the API, I don’t see the Authorization header with the idToken of the logged-in user. The result of the request is an error that says “You don’t have permission to perform this operation.”

Do I need to do something so that client passes the idToken in the header?

When I try to do client.setIdToken(idToken) before the request, I get an error saying “Unhandled Rejection (Error): Can’t refresh token.”

I also tried to do this with useApolloClient from @apollo/react-hooks, modeled after what you have in your documentation here.

import React, { useEffect } from 'react'
import { useApolloClient } from "@apollo/react-hooks"
import { withAuth } from '8base-react-sdk'

import { USER_UPDATE_STRIPE_ID_MUTATION } from '../../../apollo/user'

let CallbackContainer = (props) => {
  
  const { auth, history, location } = props

  const client = useApolloClient()

  const context = { 
    headers: { 
      authorization: `Bearer ${auth.authState.token}` 
    } 
  }

  const completeStripeConnect = async () => {
    const clientResponse = await client.mutate({ 
      mutation: USER_UPDATE_STRIPE_ID_MUTATION, 
      variables: {
        state: "Example State",
        stripe_code: "Example Stripe Code",
      },
      context
    })

    console.log('clientResponse: ', clientResponse)

  }

  useEffect(() => {
    completeStripeConnect()
  }, [])

  return null
}

CallbackContainer = withAuth(CallbackContainer)

export { CallbackContainer }

However, it looks like the Apollo client is trying to contact an endpoint at “http://localhost:3000/graphql” rather than the 8base endpoint I have set when initializing 8base’s in App.js:

import React from 'react'
import { BrowserRouter } from "react-router-dom"

import { Auth, AUTH_STRATEGIES } from '@8base/auth'
import { AppProvider } from '8base-react-sdk'

import Routes from './routes'

import theme from './themes'
import './App.css'

const authClient = Auth.createClient(
  {
    strategy: AUTH_STRATEGIES.WEB_8BASE,
    subscribable: true,
  },
  {
    domain: process.env.REACT_APP_EIGHTBASE_DOMAIN,
    clientId: process.env.REACT_APP_EIGHTBASE_CLIENT_ID,
    redirectUri: `${window.location.origin}/auth/callback`,
    logoutRedirectUri: `${window.location.origin}/logout`,
  }
)

class App extends React.PureComponent {

  onRequestSuccess = ({ operation }) => {
    const message = operation.getContext()

    if (message) {
      // eslint-disable-next-line no-console
      console.error(message)
    }
  };

  onRequestError = ({ graphQLErrors }) => {
    const hasGraphQLErrors = Array.isArray(graphQLErrors) && graphQLErrors.length > 0

    if (hasGraphQLErrors) {
      graphQLErrors.forEach(error => {
        // eslint-disable-next-line no-console
        console.error(error.message)
      });
    }
  }

  render() {
    return (
      <BrowserRouter>
        <AppProvider 
          uri={process.env.EIGHTBASE_ENDPOINT} 
          authClient={authClient} 
          onRequestSuccess={this.onRequestSuccess} 
          onRequestError={this.onRequestError}
        >
          <ThemeProvider theme={theme}>
            <CssBaseline />
            <Routes />
          </ThemeProvider>
        </AppProvider>
      </BrowserRouter>
    )
  }

}

export default App

My understanding (perhaps incorrect) is that the 8base AppProvider is initializing an Apollo Client in the background, so I’m not quite sure why the endpoint I have set there isn’t being used by the Apollo client when I try to send a query.

const { Client } = require('@8base/api-client');

const client = new Client('https://api.8base.com/workspaceId');

client.setIdToken('ID_TOKEN');

client.request(`
  query {
    user {
      id
    }
  }
`).then(console.log);

Works for me, are you sure your idToken is not expired?

I don’t advise to use @8base/api-client on the client-side. It’s just API wrapper without cache for Node JS projects. Did you try to use Apollo Client?

Ah, using @8base/api-client worked this time! Maybe the idToken was expired before.

But good to know I shouldn’t use it - I’d like to use Apollo Client instead.

See above (my second post) for my attempt at using Apollo Client. It looks like Apollo Client was using what I assume is a default endpoint ("/graphql") rather than the one I had set in the 8base-react-sdk AppProvider within App.js.

Sorry if I’m doing something basic wrong, a lot of this is new to me.

@vladimir.osipov Any feedback on how to do this with Apollo Client?

@Serena https://codesandbox.io/s/github/8base/react-sdk/tree/master/examples/with-authorization-app, this example how u can implement auth in your app with 8base React SDK which used Apollo.