I'm trying to create a browser extension using React and Apollo GraphQL. For background, I'm using the webextension-polyfill
which is why I refer to the browser
namespace as opposed to chrome
.
In my index.tsx
file, I try to set up my Apollo Client as follows:
// ... more imports ...
import App from './App'
const link = HttpLink({
uri: 'http://localhost:8000/graphql/',
});
const authLink = setContext((_, { headers }) => {
window.postMessage({ type: "GET_TOKEN" }, "*");
// I need to fetch `token` from the the result of the above postMessage
return {
headers: {
...headers,
authorization: token ? `JWT ${token}` : "",
}
}
})
export const client = new ApolloClient({
link: authLink.concat(link),
cache: new InMemoryCache()
});
ReactDOM.render(
<ApolloProvider client={client}>
<React.StrictMode>
<App />
</React.StrictMode>
</ApolloProvider>,
document.getElementById("root")
);
Normally in a regular web app you'd store your token in localStorage, and fetch it from there like so localStorage.getItem("token")
.
But since this is a browser extension, I can't use localStorage and fetch from it across all tabs. I have to use browser.storage.local
.
I can successfully save to the extension's browser.storage.local
after the user signs in, so you can assume the token is available and can be fetched.
Since you cannot interact with browser.storage.local
outside of the context of the extension, I have to send a message to my content.js
script to tell it to fetch it from storage.
This is why I have window.postMessage({ type: "GET_TOKEN" }, "*");
above.
Then in my content.js
file, I listen for the message, and send another message with the result:
window.addEventListener("message", function (event) {
...
onDidReceiveMessage(event);
})
async function onDidReceiveMessage(event) {
if (event.data.type && (event.data.type === "GET_TOKEN")) {
const payload = JSON.parse(JSON.stringify({ type: "TOKEN_RESULT", token: await browser.storage.local.get("token") }));
window.postMessage(payload, "*");
}
}
My problem is now listening for this event and using it in the index.tsx
file during my setup of Apollo Client.
In the index.tsx
file, I've tried something along the lines of:
const authLink = setContext((_, { headers }) => {
window.postMessage({ type: "GET_TOKEN" }, "*");
window.addEventListener("message", function (event) {
if (event.data.type && (event.data.type === "TOKEN_RESULT")) {
token = event.data.token.token
}
});
// the value of `event.data.token.token` in the listener is correct and successfully fetched
// but can only really be used in the listener, I need it available to be used below
// as part of this outer `setContext` for Apollo
return {
headers: {
...headers,
authorization: token ? `JWT ${token}` : "",
}
}
})
How do I fetch the token out of storage in the context of a browser extension, if I need to use it in a setup up file like the one used to setup Apollo Client?
Any help or alternative approaches would be appreciated.
question from:
https://stackoverflow.com/questions/65877921/fetching-token-from-extension-storage-in-react-apollo-graphql-browser-extensio