newsiberian / apollo-link-token-refresh

Apollo Link that performs access tokens (JWT) renew
MIT License
337 stars 45 forks source link

TypeError: response.text is not a function #39

Closed furkandmrblk closed 3 years ago

furkandmrblk commented 3 years ago

Hey, this is my first time doing something like this. Sorry in advance if I miss something important out.

So basically I am trying to implement this package into my project and I ran into the following issue: TypeError: response.text is not a function at eval (tokenRefreshLink.js?bf0b:14)

My refreshLink is looking like this:

const refreshLink = new TokenRefreshLink({
  accessTokenField: 'accessToken',
  isTokenValidOrUndefined: () => accessTokenExpired(),
  fetchAccessToken: () => fetchAccessToken(),
  handleFetch: (accessToken: string) => setAccessToken(accessToken),
  handleError: (err: Error) => {
    console.log('An error occurred');
    console.log(err);
  },
});

And my helper functions are looking like this:

let accessToken: string = '';

export const setAccessToken = (incomingToken: string): void => {
  if (!incomingToken || incomingToken === null) {
    return console.log('accessToken not found.');
  }

  accessToken = incomingToken;
};

export const getAccessToken = (): string => {
  return accessToken;
};

export const accessTokenExpired = (): boolean => {
  let isValid: boolean = undefined;

  const token: any = getAccessToken().valueOf();

  if (!token || token === null) {
    return isValid === false;
  }

  let decodedToken: any = jwt_decode(token);
  console.log('Decoded Token');

  let expiryDate = new Date(decodedToken.exp * 1000);
  let exp = decodedToken.exp * 1000;
  let dateNow = Date.now();

  // console.log(expiryDate);

  if (dateNow >= exp) {
    isValid === false;
  } else {
    isValid === true;
  }

  return isValid;
};
`

`
export const fetchAccessToken = async (): Promise<any> => {
  const payload = {
    operationName: 'updateTokens',
    variables: {},
    query:
      'mutation updateTokens {\n  updateTokens {\n    accessToken\n    __typename\n  }\n}\n',
  };
  return fetch('http://localhost:4000/graphql'!, {
    method: 'POST',
    credentials: 'include',
    body: JSON.stringify(payload),
    headers: {
      'Content-Type': 'application/json; charset=utf-8',
      Accept: 'application/json',
    },
  }).then(async (res) => {
    const response = await res.json();
    console.log('fetchAccessToken');
    console.log(response.data.updateTokens.accessToken);

    return response.data.updateTokens.accessToken;
  });
};

I don't know if you also need to see my apolloClient, but I will insert it here just in case:

export const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
  ssrMode: true,
  cache: new InMemoryCache(),
  link: from([refreshLink, authLink, errorLink, httpLink]),
  defaultOptions: {
    watchQuery: {
      fetchPolicy: 'cache-and-network',
    },
  },
});

I know that my accessTokenExpired and fetchAccessToken functions are working properly, because I am getting a new accessToken when I refresh the page. The accessTokenExpired function also correctly detects whether the token is expired or not. So I'm clueless right now what I should do to prevent this error from happening. Sorry for the inconvenience again.

furkandmrblk commented 3 years ago

Okay I think I finally solved my issue.

Here is my new fetchAccessToken function:

export const fetchAccessToken = async (): Promise<any> => {
  const response = await fetch('http://localhost:4000/graphql', {
    method: 'POST',
    credentials: 'include',
    headers: {
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      query:
        'mutation updateTokens {\n  updateTokens {\n    accessToken\n    __typename\n  }\n}\n',
    }),
  });

  return response.json();
};

And here is my updated refreshLink:

const refreshLink = new TokenRefreshLink({
  accessTokenField: 'accessToken',
  isTokenValidOrUndefined: () => accessTokenExpired(),
  fetchAccessToken: () => fetchAccessToken(),
  handleFetch: (accessToken: string) => setAccessToken(accessToken),
  handleResponse: (operation, accessTokenField) => (response) => {
    if (!response) return { accessToken: null };

    return { accessToken: response.data?.updateTokens?.accessToken };
  },
  handleError: (err: Error) => {
    console.log('An error occurred');
    console.log(err);
  },
});

Thanks anyway.