Vue-apollo: We have to reload the web page to apply auth middleware?

Created on 14 Jan 2018  路  12Comments  路  Source: vuejs/vue-apollo

Hi everyone,

Here is my setup of apollo client

const httpLink = new HttpLink({ uri: 'https://api.graph.cool/simple/v1/cjaeub9io2kcz0115e4m0ql6d' })

let token = localStorage.getItem('GC_AUTH_TOKEN')

const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: { authorization: `Bearer ${token}` }
  })
  return forward(operation)
})
const link = middlewareLink.concat(httpLink)

const apolloClient = new ApolloClient({
  link,
  cache: new InMemoryCache()
})

after login, I mean after we set localStorage token, we have to reload the web app to apply middleware to apollo client. Is there any solution for this?

Most helpful comment

Object.defineProperty(Vue.prototype, '$token', {
  get () { return token },
  set (value) { token = value },
})
this.$token = 'new-value'

All 12 comments

Why don't you update your token variable?

token = localStorage.getItem('GC_AUTH_TOKEN')

@Akryum

Thanks for reply. I put it in main.js

import Vue from 'vue'
import axios from 'axios'

import App from './App'
import router from './router'
import store from './store'

// Plugin
import Acl from './plugins/vue-acl'
import Buefy from 'buefy'
import 'mdi/css/materialdesignicons'

// Vue Apollo
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'

// Vue Electron
if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios
Vue.config.productionTip = false

// Vue Apollo
const httpLink = new HttpLink({ uri: 'https://api.graph.cool/simple/v1/cjaeub9io2kcz0115e4m0ql6d' })

let token = localStorage.getItem('GC_AUTH_TOKEN')

const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: { authorization: `Bearer ${token}` }
  })
  return forward(operation)
})
const link = middlewareLink.concat(httpLink)

const apolloClient = new ApolloClient({
  link,
  cache: new InMemoryCache()
})

// Install Plugin
Vue.use(VueApollo)
Vue.use(Buefy)
Vue.use(Acl, {
  router,
  init: 'public',
  fail: '/login'
})

const apolloProvider = new VueApollo({
  defaultClient: apolloClient
})

/* eslint-disable no-new */
new Vue({
  components: { App },
  router,
  store,
  apolloProvider,
  template: '<App/>'
}).$mount('#app')

I don't know how to update token variable from a component. Can you guide me how to do it.

Object.defineProperty(Vue.prototype, '$token', {
  get () { return token },
  set (value) { token = value },
})
this.$token = 'new-value'

Thanks for your help.

@kieusonlam Did you solve the issue? If then, can you post the working code snippet here? Thanks.

The solution worked. Just had mistake on my side. Thank you.
Fyi, here is my code snippet using apollo-boost.

// main.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import VueApollo from 'vue-apollo';
import ApolloClient from 'apollo-boost';

Vue.use(VueApollo);
Vue.config.productionTip = false;

let token = localStorage.getItem('token');
Object.defineProperty(Vue.prototype, '$token', {
  get() { return token },
  set(value) { token = value },
})

const uri = 'your-graphql-uri'

const client = new ApolloClient({
  uri,
  request: (operation) => {
    operation.setContext({
      headers: {
        Authorization: token ? `Bearer ${token}` : ''
      }
    });
  }
});

const apolloProvider = new VueApollo({
  defaultClient: client
});

new Vue({
  router,
  store,
  render: (h) => h(App),
  apolloProvider
}).$mount('#app');

In the login component after you get the token from server just add this line.
this.$token = 'some_token';

I'm having the same issue using ApolloClient. I have to refresh the page to make the ApolloClient knowing the token.

import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { CA_USER_TOKEN, CA_USER_TYPE } from '../utils/settings';

const token = localStorage.getItem(CA_USER_TOKEN)
const userType = localStorage.getItem(CA_USER_TYPE)

export const apolloClient = new ApolloClient({
link: new HttpLink({
uri: 'http://localhost:81/api',
headers: {
Authorization: Bearer + localStorage.getItem(CA_USER_TOKEN),
UserType: localStorage.getItem(CA_USER_TYPE),
},
}),
cache: new InMemoryCache(),
connectToDevTools: true,
})

const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})

Vue.use(VueApollo)

export default apolloProvider

How can I solve this?

@samuelhgf You set your headers only once.

@Akryum I didn't understand want you mean. Can tou explain what should I do, pleae?

Your object containing the headers is only created once, hence why you need to reload the page to apply new values from the local storage. See example solutions above in the thread or read the documentation.

But I will need to use the setContext, right?

My code:

`import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { CA_USER_TOKEN, CA_USER_TYPE } from '../utils/settings';

const httpLink = createHttpLink({
uri: 'http://localhost:81',
});

const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem(CA_USER_TOKEN);
const userType = localStorage.getItem(CA_USER_TYPE);

// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? Bearer ${token} : "",
UserType: userType,
}
}
});

export const apolloClient = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
connectToDevTools: true,
});

const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})

Vue.use(ApolloClient)

export default apolloProvider`

But I'm getting this error: Uncaught TypeError: Cannot set property 'defaultOptions' of null

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wangxiangyao picture wangxiangyao  路  4Comments

jsrkstr picture jsrkstr  路  3Comments

anymost picture anymost  路  3Comments

alsofronie picture alsofronie  路  3Comments

beeplin picture beeplin  路  4Comments