Skip to content

Instantly share code, notes, and snippets.

@CryceTruly
Created February 22, 2022 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CryceTruly/31cdc3c7b06b032dad4302590a390ad0 to your computer and use it in GitHub Desktop.
Save CryceTruly/31cdc3c7b06b032dad4302590a390ad0 to your computer and use it in GitHub Desktop.
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios, {AxiosError} from 'axios';
import {logOutUserLocal} from 'redux/actions/auth/logout/clearAllUser';
import store from 'redux/store';
import envs from 'config/env';
// Getting token from local Storage
async function getLocalToken() {
const token = await AsyncStorage.getItem('token');
return `Bearer ${token}`;
}
// Add a setToken method to the instance to dynamically add the latest token to the header after login, and save the token in the local Storage
const setNewToken = (token: string) => {
instance.defaults.headers.Authorization = `Bearer ${token}`;
AsyncStorage.setItem('token', token);
};
async function refreshToken() {
// Instance is the axios instance created in current request.js
const token = await AsyncStorage.getItem('refresh_token');
const res = await instance.post('/auth/token/refresh/', {
refresh: token,
});
return res.data.access;
}
// Create an axios instance
const instance = axios.create({
baseURL: envs.BACKEND_URL,
headers: {
'Content-Type': 'application/json',
Authorization: getLocalToken(), // headers settoken
},
});
instance.interceptors.request.use(
async config => {
const token = await AsyncStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => {
return Promise.reject(error);
},
);
// Is the marker being refreshed?
let isRefreshing = false;
// Retry queue, each item will be a function to be executed
let requests = [] as Array<any>;
instance.interceptors.response.use(
response => {
return response;
},
(error: AxiosError) => {
if (
error.response?.data?.detail ===
'Given token not valid for any token type'
) {
const config = error.config;
if (!isRefreshing) {
isRefreshing = true;
return refreshToken()
.then(access => {
setNewToken(access);
config.headers['Authorization'] = `Bearer ${access}`;
// access has been refreshed to retry requests from all queues
requests.forEach(cb => cb(access));
requests = [];
return instance(config);
})
.catch(error => {
logOutUserLocal(store.dispatch);
})
.finally(() => {
isRefreshing = false;
});
} else {
// token is being refreshed and a promise that resolve has not been executed is returned
return new Promise(resolve => {
// Put resolve in the queue, save it in a function form, and execute it directly after token refreshes
requests.push((token: string) => {
config.headers['Authorization'] = `Bearer ${token}`;
resolve(instance(config));
});
});
}
}
return Promise.reject(error);
},
);
export default instance;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment