Skip to content

Instantly share code, notes, and snippets.

@lindesvard
Created June 13, 2018 11:09
Show Gist options
  • Save lindesvard/8bd0aa751a4c4e84072000222232f648 to your computer and use it in GitHub Desktop.
Save lindesvard/8bd0aa751a4c4e84072000222232f648 to your computer and use it in GitHub Desktop.
ApolloClient with JWT auth and refetch jwt token with refreshtoken
import config from 'config'
import { getAccessToken } from 'libs/storage'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { InMemoryCache } from 'apollo-cache-inmemory'
import customFetch from './customFetch'
const httpLink = createHttpLink({
uri: config.GRAPHQL_URL,
fetch: customFetch,
})
const getAuthHeaders = async (currentToken = null) => {
const token = currentToken || (await getAccessToken())
return token ? { authorization: `Bearer ${token}` } : {}
}
const authLink = setContext(async (_, { headers }) => ({
headers: {
...headers,
...(await getAuthHeaders()),
},
}))
export default new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})
import { get } from 'lodash'
import { getRefreshToken, setAccessToken } from './storage'
import config from 'config'
export default async (uri, options) => {
this.tokenRequest = null
const initialRequest = await fetch(uri, options)
const clonedRequest = await initialRequest.clone()
const response = await clonedRequest.json()
const accessTokenHasExpired =
get(response, 'errors', []).filter(error => error.message === 'jwtExpired')
.length > 0
if (accessTokenHasExpired && !this.tokenRequest) {
console.log('accessToken has expired, try getting a new one')
this.tokenRequest = await fetch(config.API_URL + '/auth/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
refreshToken: await getRefreshToken(),
}),
})
if (this.tokenRequest.status !== 200) {
// TODO: clear everything about the user
// and send them to home screen
console.log('Could not update the accessToken #1')
return initialRequest
}
const { accessToken } = await this.tokenRequest.json()
options.headers.authorization = `Bearer ${accessToken}`
console.log('Fetch with new accessToken', accessToken)
this.tokenRequest = null
setAccessToken(accessToken)
return fetch(uri, options).catch(res => {
console.log('Could not update the accessToken #2')
})
}
return initialRequest
}
import { AsyncStorage } from 'react-native'
const ACCESS_TOKEN = 'accessToken'
const REFRESH_TOKEN = 'refreshToken'
// for some caching
let accessToken = null
let refreshToken = null
export const setAccessToken = token => {
accessToken = token
return AsyncStorage.setItem(ACCESS_TOKEN, token)
}
export const setRefreshToken = token => {
refreshToken = token
return AsyncStorage.setItem(REFRESH_TOKEN, token)
}
export const getAccessToken = async () => {
if (accessToken) return accessToken
accessToken = await AsyncStorage.getItem(ACCESS_TOKEN)
return accessToken
}
export const getRefreshToken = async () => {
if (refreshToken) return refreshToken
refreshToken = await AsyncStorage.getItem(REFRESH_TOKEN)
return refreshToken
}
export const clearTokens = () => {
accessToken = null
refreshToken = null
return Promise.all([
AsyncStorage.removeItem(ACCESS_TOKEN),
AsyncStorage.removeItem(REFRESH_TOKEN),
])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment