-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterceptor.js
130 lines (110 loc) · 3.28 KB
/
interceptor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import axios from "axios";
// Axios defaults
const baseURL = "https://example.com";
axios.defaults.baseURL = baseURL;
// Active http requests
let activeRequests = 0;
/**
* Request interceptor
* Adds a default configuration to axios (baseUrl, token, content-type, etc.)
* Counts active http requests
*/
axios.interceptors.request.use(
config => {
let token = null;
if (config.url === "/auth/refresh") {
token = localStorage.getItem("refresh_token") || null;
} else {
token = localStorage.getItem("access_token") || null;
}
if (token != null) {
config.headers.Authorization = `Bearer ${token}`;
}
// Count plus active requests to our API
activeRequests++;
return config;
},
err => {
return Promise.reject(err);
}
);
/**
* Response interceptor for handling 401 error
* Queueing failed requests in an array
* Automatically trying refresh token after the first fail
* Refreshing the token only once and applying the new token to the requests which were queued
* Counts finished http requests
*/
// Refreshing flag
let isRefreshing = false;
let subscribers = [];
function subscribeTokenRefresh(cb) {
subscribers.push(cb);
}
function onRrefreshed(token) {
if (activeRequests > 0) {
return setTimeout(onRrefreshed, 100);
}
subscribers.map(cb => cb(token));
subscribers = [];
}
axios.interceptors.response.use(
response => {
// Count minus active requests to our API
activeRequests--;
return response;
},
error => {
// Count minus active requests to our API
activeRequests--;
if (error.response) {
// The request was made and the server responded with a status code
// That falls out of the range of 2xx+
const { config, response: { status } } = error;
const originalRequest = config;
// The request failed because it lacks valid authentication credentials
if (status === 401) {
if (!isRefreshing && !subscribers.length) {
isRefreshing = true;
refreshToken()
.then(response => {
const { data } = response;
isRefreshing = false;
onRrefreshed(data.access_token);
localStorage.setItem("access_token", data.access_token);
localStorage.setItem("refresh_token", data.refresh_token);
})
.catch(err => {
forceLogout();
});
}
const requestSubscribers = new Promise(resolve => {
subscribeTokenRefresh(token => {
originalRequest.headers.Authorization = `Bearer ${token}`;
resolve(axios(originalRequest));
});
});
return requestSubscribers;
}
} else if (error.request) {
// The request was made but no response was received
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log("Error", error.message);
}
return Promise.reject(error.response);
}
);
// Refresh token function
function refreshToken() {
return axios.post("/auth/refresh").then(function(response) {
return response;
});
}
// Logout function, used if token refreshing fails
function forceLogout() {
isRefreshing = false;
localStorage.clear();
window.location = "/auth/login";
}