kminny
kminny

Reputation: 239

Apollo graphql setting header to authmiddleware not working

I am using react-native and apollo client and if I try to set header by jwt stored in AsyncStorage, it seems not working.
Other resolvers which doesn't need header works very well. My code is like below.

import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-link";
import { createHttpLink } from "apollo-link-http";
import AsyncStorage from "@react-native-community/async-storage";

const cache = new InMemoryCache();

const getToken = async () => {
  const token = await AsyncStorage.getItem("jwt");

  if (token) {
    return token;
  } else {
    return null;
  }
};

const httpLink = new createHttpLink({
  uri: ""
});

const authLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: {
      "X-JWT": getToken()
      // this is where I set headers by getToken function
      // If I change function getToken to real token in string type, it works then
    }
  });

  return forward(operation);
});

const client = new ApolloClient({
  cache: cache,
  link: authLink.concat(httpLink)
});

export default client;

Like I commented in the code, calling getToken function is not working what I expected. I think I should have more knowledge of async and await, but I don't get it what is the real problem.

The error message I get from console is jwt malformed. Please let me know how to fix this problem

Upvotes: 5

Views: 5405

Answers (5)

Muhammad Numan
Muhammad Numan

Reputation: 25423

dont use operation.setContext try to use setContext from @apollo/client/link/context like this

import { setContext } from "@apollo/client/link/context";
import {
  ApolloClient,
  InMemoryCache,
  ApolloLink,
} from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import AsyncStorage from "@react-native-community/async-storage";

const httpLink = createHttpLink();

const authLink = setContext(async (_, { headers = {} }) => {
  const token = await AsyncStorage.getItem("jwt");
  return {
    headers: {
      ...headers,
      "X-JWT": token,
    },
  };
});

const client = new ApolloClient({
  link: ApolloLink.from([authLink, httpLink]),
  cache: new InMemoryCache(),
});

export default client;

Upvotes: 0

arnaldo.crescente
arnaldo.crescente

Reputation: 41

Thank you @аlex dykyі, this is my latest version

    import { Auth } from "@aws-amplify/auth";
    import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from "@apollo/client";
    import { setContext } from "@apollo/client/link/context";
    
    export const getGraphqlClient = (url: string) => {
      const getToken = async () => {
        return (await Auth.currentSession()).getIdToken().getJwtToken();
      };
    
      const authMiddleware = setContext(async (operation) => {
        return {
          headers: {
            authorization: `Bearer ${await getToken()}` || null,
          },
        };
      });
    
      const link = ApolloLink.from([authMiddleware]);
      const httpLink = createHttpLink({ uri: url });
    
      return new ApolloClient({
        link: link.concat(httpLink),
        cache: new InMemoryCache(),
      });
    };

Upvotes: 0

аlex
аlex

Reputation: 5698

    import { setContext } from '@apollo/client/link/context';
    
    // import getJwtToken // return string
    
    const authMiddleware = setContext(async (operation) =>{
        const token = await getJwtToken();
        return {
          headers: {
            authorization: token || null,
          },
        };
    });
    
    
    const link = ApolloLink.from([
      authMiddleware,
      // ...
      
    ]);

Upvotes: 4

Asaf Aviv
Asaf Aviv

Reputation: 11810

Try to use setContext directly

import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { setContext } from "apollo-link-context";
import { InMemoryCache } from "apollo-cache-inmemory";
import AsyncStorage from "@react-native-community/async-storage";

const httpLink = createHttpLink();

const authLink = setContext(async (_, { headers }) => {
  const token = await AsyncStorage.getItem("jwt");

  return {
    headers: {
      ...headers,
      "X-JWT": token || null
    }
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

export default client;

Upvotes: 16

Tobias Lins
Tobias Lins

Reputation: 2651

The problem is that you are not awaiting the promise. That means it should be await getToken(). In order to make this working the ApolloLink function should also be async.

This would decrease your performance a little because on every request it would read the token from your AsyncStore. I would do it like that:

import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-link";
import { createHttpLink } from "apollo-link-http";
import AsyncStorage from "@react-native-community/async-storage";

const cache = new InMemoryCache();

let token
const getToken = async () => {
  if(token) return token;

  token = await AsyncStorage.getItem("jwt");

  return token || null;
};

const httpLink = new createHttpLink({
  uri: ""
});

const authLink = new ApolloLink(async (operation, forward) => {
  operation.setContext({
    headers: {
      "X-JWT": await getToken()
      // this is where I set headers by getToken function
      // If I change function getToken to real token in string type, it works then
    }
  });

  return forward(operation);
});

const client = new ApolloClient({
  cache: cache,
  link: authLink.concat(httpLink)
});

export default client;

Upvotes: -1

Related Questions