vue.jshttp-headersvue-apollo

How to set authentications headers with Vue apollo and composition api?


I've build my app with Vite. I read many documents on web about the topic but I'm still very confused. I've a login form that send credentials to a protected view. When post the data I set the headers and store the Bearer token in the local storage. The problem is that it doesn't work cause the Bearer token result equal to null. Only when I logout the token is set in the headers.

That's how is the header when I log in

enter image description here

And here how it's set when I log out...

enter image description here

My main.js code is this:

import { createApp, provide, h } from "vue";
import {
  ApolloClient,
  createHttpLink,
  InMemoryCache,
} from "@apollo/client/core";
import { DefaultApolloClient } from "@vue/apollo-composable";

import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";

import { provideApolloClient } from "@vue/apollo-composable";

const authToken = localStorage.getItem("auth-token");

const httpLink = createHttpLink({
  uri: "http://localhost/graphql",
  headers: {
    Authorization: "Bearer " + authToken,
  },
});

const cache = new InMemoryCache();

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

provideApolloClient(apolloClient);

const app = createApp({
  setup() {
    provide(DefaultApolloClient, apolloClient);
  },

  render: () => h(App),
});

app
  .use(router)
  .use(createPinia())
  .mount("#app");

and this is my routes.js

const router = createRouter({
  history: createWebHistory(),
  routes
})

router.beforeEach((to, from, next) => {

    const requiresAuth = to.matched.some(record => record.meta.requiresAuth);

    const isAuthenticated = localStorage.getItem('auth-token');

    if(requiresAuth && isAuthenticated===null){
      next('/auth/login');
    }else {
      next();
    }

});

I'm surely making some mistakes in my main.js but I cannot understand what's wrong. I'm very confused :-/ Thanks to who'll be able to help me.


Solution

  • Try using a helper function to get the token from local storage; I'm using this method and it's working fine for me. To get your code more organized, create a separate folder to define the apollo client. Here is the code:

    // apolloClient.ts
    import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client/core";
    
    function getHeaders() {
      const headers: { Authorization?: string; "Content-Type"?: string } = {};
      const token = localStorage.getItem("access-token");
      if (token) {
        headers["Authorization"] = `Bearer ${token}`;
      }
      headers["Content-Type"] = "application/json";
      return headers;
    }
    
    // Create an http link:
    const httpLink = new HttpLink({
      uri: `${import.meta.env.VITE_API_URL}/graphql`,
      fetch: (uri: RequestInfo, options: RequestInit) => {
        options.headers = getHeaders();
        return fetch(uri, options);
      },
    });
    
    // Create the apollo client
    export const apolloClient = new ApolloClient({
      cache: new InMemoryCache(),
      link: httpLink,
      defaultOptions: {
        query: {
          errorPolicy: "all",
        },
        mutate: {
          errorPolicy: "all",
        },
      },
    });
    

    Then you can use it in your main.ts like this:

    // main.ts
    import { createApp, h } from "vue";
    import { provideApolloClient } from "@vue/apollo-composable";
    import App from "./App.vue";
    import { apolloClient } from "./apolloClient";
    
    
    const app = createApp({
      setup() {
        provideApolloClient(apolloClient);
      },
      render: () => h(App),
    });
    
    
    app.mount("#app");