UNPKG

apollo-link-refresh-token

Version:

A link to refresh auth tokens on authentication errors

116 lines (96 loc) 5.06 kB
# apollo-link-refresh-token A link to refresh auth tokens on authentication errors ## Getting started Install the package: ``` yarn add apollo-link-refresh-token ``` Add the link to your apollo client: _Note that your implementation will likely change based on your specific parameters._ ```typescript import { ApolloClient } from 'apollo-client'; import { getTokenRefreshLink, FetchNewAccessToken, } from 'apollo-link-refresh-token'; import jwtDecode from 'jwt-decode'; import { authLink, errorLink, httpLink } from './links'; const isTokenValid = (token: string): boolean => { const decodedToken = jwtDecode<{ [key: string]: number }>(token); if (!decodedToken) { return false; } const now = new Date(); return now.getTime() < decodedToken.exp * 1000; }; const fetchNewAccessToken: FetchNewAccessToken = async refreshToken => { if (!process.env.REACT_APP_API_URL) { throw new Error( '.env.REACT_APP_API_URL must be set to use refresh token link' ); } try { const fetchResult = await fetch(process.env.REACT_APP_API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: ` mutation { refreshTokens(input: { refreshToken: "${refreshToken}" }) { accessToken refreshToken errors { field message } } } `, }), }); const refreshResponse = await fetchResult.json(); if ( !refreshResponse || !refreshResponse.data || !refreshResponse.data.refreshTokens || !refreshResponse.data.refreshTokens.accessToken ) { return undefined; } return refreshResponse.data.refreshTokens.accessToken; } catch (e) { throw new Error('Failed to fetch fresh access token'); } }; const refreshTokenLink = getRefreshTokenLink({ authorizationHeaderKey: 'Authorization', fetchNewAccessToken, getAccessToken: () => localStorage.getItem('access_token'), getRefreshToken: () => localStorage.getItem('refresh_token'), isAccessTokenValid: accessToken => isTokenValid(accessToken), isUnauthenticatedError: graphQLError => { const { extensions } = graphQLError; if (extensions && extensions.code && extensions.code === 'UNAUTHORIZED') { return true; } return false; }, }); export const client = new ApolloClient({ link: ApolloLink.from([authLink, refreshTokenLink, errorLink, httpLink]), cache, }); ``` ## Options | Option | Type | Default | Description | | ---------------------- | ------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | authorizationHeaderKey | string | -- | Name of the authorization header on your requests. Is used to update the headers before retrying the failed request | | fetchNewAccessToken | (refreshToken: string) => Promise<string \| undefined> | -- | A function returning a promise to fetch and return the new refresh token string. | | getAccessToken | () => string \| undefined \| null | -- | A function to return the current access token. Is used to ensure that the user should be logged in, and to pass into isAccessTokenValid. | | getRefreshToken | () => string \| undefined \| null | -- | A function to return the current refreshToken. Is used to ensure that refresh is possible. It is passed to fetchNewAccessToken(). | | isAccessTokenValid | (accessToken?: string) => boolean | -- | A function that takes the access token (from getAccessToken) and returns true if the access token is valid. If the token is valid, refresh won't occur. | | isUnauthenticatedError | (graphQLError: GraphQLError) => boolean | -- | A function that determines whether the error from the current operation warrants a token refresh. Usually looks for an unauthenticated code. | | onFailedRefresh? | (error: any) => void | -- | A function to handle errors when the refresh fails. | | onSuccessfulRefresh? | (refreshToken: string) => void | -- | A function ot handle successful refresh. |