Apollo graphql setting header to authmiddleware not working
Asked Answered
D

5

5

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

Doleful answered 1/9, 2019 at 15:19 Comment(2)
An async function always returns a promise so you will get a pending promise. Can you try making the ApolloLink callback async and set "X-JWT": await getToken()Accumulative
If I do like that, it gives me another error message Network error: inner.subscribe is not a function. @AsafAvivDoleful
A
16

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;
Accumulative answered 1/9, 2019 at 16:1 Comment(0)
M
4
    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,
      // ...
      
    ]);
Maclay answered 5/5, 2021 at 6:17 Comment(1)
This answer helped me the most since I was chaining middleware with from.Chenab
M
0

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(),
      });
    };
Meerkat answered 17/11, 2022 at 16:47 Comment(0)
G
0

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;
Gasiform answered 19/12, 2022 at 21:0 Comment(0)
P
-1

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;
Pluck answered 1/9, 2019 at 15:56 Comment(1)
new ApolloLink does not expect a promise, so this is not possibleAronoff

© 2022 - 2024 — McMap. All rights reserved.