Skip to content

Instantly share code, notes, and snippets.

@bzhr
Created May 14, 2020 16:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bzhr/cd047e751a6293756db474695f40bae0 to your computer and use it in GitHub Desktop.
Save bzhr/cd047e751a6293756db474695f40bae0 to your computer and use it in GitHub Desktop.
Apollo Refresh Token
import React from "react";
import ReactDOM from "react-dom";
import ApolloClient from "apollo-client";
import { ApolloProvider } from "@apollo/react-hooks";
import { ApolloLink, fromPromise } from "apollo-link";
import { onError } from "apollo-link-error";
// import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { createUploadLink } from "apollo-upload-client";
import { setContext } from "apollo-link-context";
import { InMemoryCache } from "apollo-cache-inmemory";
import "./assets/main.css";
import { signOut } from "./components/Auth";
import { getToken, getRefreshToken, getNewToken } from "./constants/token";
const API_URL = process.env.REACT_APP_API_URL;
const httpLink = createUploadLink({
uri: API_URL ? API_URL : "/graphql",
credentials: "omit",
});
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem("token");
return {
headers: {
...headers,
authorization: token ? `JWT ${token}` : "",
},
};
});
let isRefreshing = false;
let pendingRequests = [];
const resolvePendingRequests = () => {
pendingRequests.map((callback) => callback());
pendingRequests = [];
};
const errorLink = onError(
({ graphQLErrors, networkError, operation, forward, location, ...other }) => {
console.log("On error");
console.log(graphQLErrors, networkError, other);
// TODO --- On error message invalid token clear local storage
if (graphQLErrors && graphQLErrors.filter((e) => e).length > 0) {
console.log("Errors: ", graphQLErrors);
for (let err of graphQLErrors) {
console.log("Message: ", err.message);
if (err.message.includes("You do not have permission")) {
const token = getToken();
const refreshToken = getRefreshToken();
console.log("Token, refresh", token, refreshToken);
if (token && refreshToken) {
console.log("In if condition");
let forward$;
if (!isRefreshing) {
isRefreshing = true;
forward$ = fromPromise(
getNewToken(client)
.then(({ data: { refreshToken } }) => {
console.log("Promise data: ", refreshToken);
if (refreshToken && refreshToken.success) {
localStorage.setItem("token", refreshToken.token);
localStorage.setItem(
"refreshToken",
refreshToken.refreshToken
);
resolvePendingRequests();
} else {
signOut();
}
return refreshToken.token;
})
.catch((error) => {
// Handle token refresh errors e.g clear stored tokens, redirect to login, ...
console.log("Error after setting token: ", error);
pendingRequests = [];
return;
})
.finally(() => {
console.log("Finally");
isRefreshing = false;
})
).filter((value) => {
console.log("In Filter: ", value);
return Boolean(value);
});
} else {
console.log("In else condition");
// Will only emit once the Promise is resolved
forward$ = fromPromise(
new Promise((resolve) => {
console.log("In else condition Promise");
pendingRequests.push(() => resolve());
})
);
}
return forward$.flatMap(() => {
console.log("Forwarding!");
console.log(operation);
return forward(operation);
});
}
// else {
// // If there's no token, then sign out user
// console.log("There's no token, sign out the user", signOut);
// signOut();
// }
}
}
}
if (networkError) {
console.log("Network error: ", networkError);
}
}
);
const links = [errorLink, authLink, httpLink];
const link = ApolloLink.from(links);
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
fetchOptions: {
mode: "no-cors",
},
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById("root")
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
@khaphannm
Copy link

Hi, could u show me the refreshToken function pls ?

@bzhr
Copy link
Author

bzhr commented Aug 3, 2020

That one is specific to your backend.

@khaphannm
Copy link

I used graphql, I had one mutation called refreshToken(), but cannot execute that because ApolloClient not yet initialized. Do u have any idea ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment