admin管理员组文章数量:1279112
I am trying to fetch protected resource from my graphql server using nextJs and apollo client. I stored the authorization token in the client browser (localstorage) and try to read the token from apolloClient.Js file; but it throws a ReferenceError (ReferenceError: localStorage is not defined). This makes me to understand quickly that the server side was trying to reference localStorage from the backend; but fails because it is only available in the client. My question is, what is the best way to solve this issue? I am just using apollo client for the first time in my project. I have spent more than 10 hours trying to figure out the solution to this problem. I have tried so many things on web; not lucky to get the solution. Here is the code am using in apolloClient file:
import { useMemo } from 'react'
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
import { concatPagination } from '@apollo/client/utilities'
import { GQL_URL } from '../utils/api'
let apolloClient
const authToken = localStorage.getItem('authToken') || '';
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: new HttpLink({
uri: GQL_URL, // Server URL (must be absolute)
credentials: 'include', // Additional fetch() options like `credentials` or `headers`
headers: {
Authorization: `JWT ${authToken}`
}
}),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
allPosts: concatPagination(),
},
},
},
}),
})
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient()
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// gets hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState)
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === 'undefined') return _apolloClient
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient
return _apolloClient
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState])
return store
}
I am trying to fetch protected resource from my graphql server using nextJs and apollo client. I stored the authorization token in the client browser (localstorage) and try to read the token from apolloClient.Js file; but it throws a ReferenceError (ReferenceError: localStorage is not defined). This makes me to understand quickly that the server side was trying to reference localStorage from the backend; but fails because it is only available in the client. My question is, what is the best way to solve this issue? I am just using apollo client for the first time in my project. I have spent more than 10 hours trying to figure out the solution to this problem. I have tried so many things on web; not lucky to get the solution. Here is the code am using in apolloClient file:
import { useMemo } from 'react'
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
import { concatPagination } from '@apollo/client/utilities'
import { GQL_URL } from '../utils/api'
let apolloClient
const authToken = localStorage.getItem('authToken') || '';
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: new HttpLink({
uri: GQL_URL, // Server URL (must be absolute)
credentials: 'include', // Additional fetch() options like `credentials` or `headers`
headers: {
Authorization: `JWT ${authToken}`
}
}),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
allPosts: concatPagination(),
},
},
},
}),
})
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient()
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// gets hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState)
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === 'undefined') return _apolloClient
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient
return _apolloClient
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState])
return store
}
Share
Improve this question
edited Jul 23, 2020 at 12:34
Emeka Augustine
asked Jul 23, 2020 at 12:19
Emeka AugustineEmeka Augustine
9311 gold badge12 silver badges17 bronze badges
6
- 1 Are you getting the error on the server or on the client? – Kisinga Commented Jul 23, 2020 at 14:44
- The error is from the server! – Emeka Augustine Commented Jul 23, 2020 at 15:50
- please post your server code as well – Kisinga Commented Jul 23, 2020 at 15:50
- I mean the server side of next js; no error from my graphql server – Emeka Augustine Commented Jul 23, 2020 at 16:49
- Did you find a solution to this? I haven't been able to add authorization header because the Apollo Client instance created in the server is passed to the client, and you can't access any of the cookies or localstorage in the server. – Danny Commented Aug 4, 2020 at 7:48
2 Answers
Reset to default 7I was able to solve the problem by accessing the local storage only when the window object is not 'undefined'; since it will be 'undefined' in the server side. This will work well because we don't want the server to access local storage.
import { useMemo } from 'react'
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { GQL_URL } from '../utils/api'
let apolloClient
function createApolloClient() {
// Declare variable to store authToken
let token;
const httpLink = createHttpLink({
uri: GQL_URL,
credentials: 'include',
});
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
if (typeof window !== 'undefined') {
token = localStorage.getItem('authToken');
}
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
Authorization: token ? `JWT ${token}` : "",
}
}
});
const client = new ApolloClient({
ssrMode: typeof window === 'undefined',
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
return client;
}
I can see this issue has been solved. But only partially. Right now this is fine for making authorized client-side queries but if someone is trying to make an authorized query on the server-side, then this would be an issue as it doesn't have access to local storage.
So modifying this :
//AUTH_TOKEN is the name you've set for your cookie
let apolloClient;
const httpLink = createHttpLink({
uri: //Your URL,
});
const getAuthLink = (ctx) => {
return setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: isSSR()
? ctx?.req?.cookies[AUTH_TOKEN] // server-side auth token
: getPersistedAuthToken(), /* This is your auth token from
localstorage */
},
};
});
};
function createApolloClient(ctx) {
return new ApolloClient({
ssrMode: typeof window === undefined,
link: from([getAuthLink(ctx), httpLink]),
cache: new InMemoryCache(),
});
}
export function initializeApollo({ initialState = null, ctx = null }) {
const _apolloClient = apolloClient ?? createApolloClient(ctx);
if (initialState) {
const existingCache = _apolloClient.extract();
_apolloClient.cache.restore({ ...existingCache, ...initialState });
}
if (isSSR()) return _apolloClient;
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
The getServerSide function would look like this:
export async function getServerSideProps(ctx) {
const { req } = ctx;
if (req?.cookies[AUTH_TOKEN]) {
const apolloClient = initializeApollo({ initialState: null, ctx });
try {
const { data } = await apolloClient.query({
query: GET_USER_DETAILS,
});
// Handle what you want to do with this data / Just cache it
} catch (error) {
const gqlError = error.graphQLErrors[0];
if (gqlError) {
//Handle your error cases
}
}
}
return {
props: {},
};
}
This way the apollo client can be used to make authorized calls on the server-side as well.
本文标签:
版权声明:本文标题:javascript - The best way to pass authorization header in nextJs using Apollo client? ReferenceError: localStorage is not define 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741264421a2368200.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论