vuejs / apollo

🚀 Apollo/GraphQL integration for VueJS
http://apollo.vuejs.org
MIT License
6k stars 516 forks source link

Authentification issue #120

Closed jeromeky closed 6 years ago

jeromeky commented 6 years ago

Hi guys,

I'm using graph.cool as a graphQL baas, and they have a query to get the current logged-in user https://www.graph.cool/docs/faq/graphcool-session-user-goij0cooqu/

However when I'm doing the following scenario :

  1. Sign in as User A
  2. Do a query to get the current user, It will return User A
  3. Sign out
  4. Sign in as User B
  5. Do a query to get the current user, It will return User A

The issue is at point 5, the current user returned is User A, and not B.

I checked that the token is correctly removed in point 3, and we set the correct token from User B at point 4.

Also used the Apollo client chrome dev tool, and when I'm doing a query from it after logged in as User B, it will correctly return the User B.

So far I found out that If I refresh the page after signing out, it will correctly return the correct User.

This is how my integration looks like

main.js

import { ApolloClient, createNetworkInterface } from 'apollo-client'
import VueApollo from 'vue-apollo'

const networkInterface = createNetworkInterface({ uri: 'uri' })

networkInterface.use([{
  applyMiddleware (req, next) {
    if (!req.options.headers) {
      req.options.headers = {}  // Create the header object if needed.
    }
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem('USER_TOKEN')
    req.options.headers.authorization = token ? `Bearer ${token}` : null
    next()
  }
}])

// Create the apollo client
const apolloClient = new ApolloClient({
  networkInterface,
  connectToDevTools: true
})

// Install the vue plugin
Vue.use(VueApollo)

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

<template>
  <div class="hello">
    <button @click="login('user1@email.com', 'password')">Login user 1</button>
    <button @click="login('user2@email.com', 'password')">Login user 2</button>
    <button @click="loadCurrentUser">Load user</button>
    <button @click="logout">logout</button>
    <p>
      {{user}}
    </p>
  </div>
</template>

<script>
import gql from 'graphql-tag'

const SignInQuery = gql `
  mutation signinUser($email: String!, $password: String!) {
    signinUser(
      email: {
        email: $email,
        password: $password
      }
    ) {
      token
      user {
        id
      }
    }
  }
`

const QueryUser = gql `
query {
  user {
    id,
    firstName,
    lastName,
    email
  }
}`

export default {
  name: 'hello',
  data () {
    return {
      user: {}
    }
  },
  methods: {
    login (email, password) {
      this.$apollo.mutate({
        mutation: SignInQuery,
        variables: {
          email,
          password
        }
      }).then((response) => {
        localStorage.setItem('USER_TOKEN', response.data.signinUser.token)
        return this.getCurrentUser()
      }).then((response) => {
        this.user = response.data
      }).catch((error) => {
        console.log(error)
      })
    },
    logout () {
      this.user = {}
      localStorage.setItem('USER_TOKEN', null)
    },
    loadCurrentUser () {
      this.getCurrentUser().then((response) => {
        this.user = response.data
      })
    },
    getCurrentUser () {
      return this.$apollo.query({
        query: QueryUser
      })
    }
  }
}
</script>

Is my integration is wrong ? Or is there an issue when you set a new Authentification header.

Thanks for your help.

ameistad commented 6 years ago

I think the issue is that Apollo is not detecting that the token changed in localStorage and is using the token from the previous user. I had similar issues and resolved it by using location.reload() in the login() callback.

I really don't know if this is the best way to do it and would appreciate it if someone could provide a better way to implement this.

jeromeky commented 6 years ago

Yes so far, I fixed that by doing a location.reload() in my logout method.

duyduc-nguyen commented 6 years ago

This issue comes from Apollo Cache (store). You need to update the store with new value after re-login.

Akryum commented 6 years ago

I think you should use await apolloClient.resetStore() when you login or logout the user.