-
-
Save ashhitch/a6fc9a0b877c36c968a257d3eb9ba584 to your computer and use it in GitHub Desktop.
Apollo refresh auth token link. It tries to refresh user access token on the fly when API throws out an UNAUTHENTICATED error. If multiple requests fails at the same time it queues them to re-try them later if we are able to get a new access token, otherwise we logout the user and redirect him to the login page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { onError } from 'apollo-link-error'; | |
import { Observable } from 'apollo-link'; | |
import { buildAuthHeader } from 'utils/requests'; | |
import { getProvider as getGlobalProvider } from 'GlobalState'; | |
let isFetchingToken = false; | |
let tokenSubscribers = []; | |
function subscribeTokenRefresh(cb) { | |
tokenSubscribers.push(cb); | |
} | |
function onTokenRefreshed(err) { | |
tokenSubscribers.map(cb => cb(err)); | |
} | |
/* eslint-disable consistent-return */ | |
const refreshAuthTokenLink = () => | |
onError( | |
({ graphQLErrors, networkError, operation, response, forward }) => | |
new Observable(async observer => { | |
if (graphQLErrors) { | |
graphQLErrors.map(async ({ extensions }, index) => { | |
switch (extensions.code) { | |
case 'UNAUTHENTICATED': { | |
const retryRequest = () => { | |
operation.setContext({ | |
headers: { | |
...headers, | |
Authorization: buildAuthHeader( | |
globalProvider.authAccessToken(), | |
).Authorization, | |
}, | |
}); | |
const subscriber = { | |
next: observer.next.bind(observer), | |
error: observer.error.bind(observer), | |
complete: observer.complete.bind(observer), | |
}; | |
return forward(operation).subscribe(subscriber); | |
}; | |
const { headers } = operation.getContext(); | |
const globalProvider = await getGlobalProvider(); | |
if (!isFetchingToken) { | |
isFetchingToken = true; | |
try { | |
await globalProvider.refreshAccessTokenReq(); | |
isFetchingToken = false; | |
onTokenRefreshed(null); | |
tokenSubscribers = []; | |
return retryRequest(); | |
} catch (e) { | |
onTokenRefreshed( | |
new Error('Unable to refresh access token'), | |
); | |
tokenSubscribers = []; | |
isFetchingToken = false; | |
await globalProvider.logOut({ isForced: true }); | |
return observer.error(graphQLErrors[index]); | |
} | |
} | |
const tokenSubscriber = new Promise(resolve => { | |
subscribeTokenRefresh(errRefreshing => { | |
if (!errRefreshing) return resolve(retryRequest()); | |
}); | |
}); | |
return tokenSubscriber; | |
} | |
default: | |
return observer.next(response); | |
} | |
}); | |
} | |
if (networkError) { | |
return observer.error(networkError); | |
} | |
}), | |
); | |
export default refreshAuthTokenLink; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment