Skip to content

Commit c9c08ed

Browse files
committed
feat: Add Authorization Error Handler (kookmin-sw#83)
1 parent e5528a8 commit c9c08ed

File tree

2 files changed

+54
-50
lines changed

2 files changed

+54
-50
lines changed

src/app/lib/axios.ts

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,71 @@
11
'use client';
22

3-
import axios, {
4-
type AxiosError,
5-
type AxiosRequestConfig,
6-
type AxiosResponse,
7-
} from 'axios';
8-
import { useRouter } from 'next/navigation';
3+
import axios, { type AxiosError, type AxiosResponse } from 'axios';
94

10-
import { getUserData, postTokenRefresh, useAuthActions } from '@/features/auth';
11-
import { load } from '@/shared/storage';
5+
import { postTokenRefresh } from '@/features/auth';
6+
import { load, save } from '@/shared/storage';
7+
import { type FailureDTO } from '@/shared/types';
128

139
let isRefreshing = false;
10+
let refreshSubscribers: Array<(token: string) => void> = [];
11+
12+
const subscribeTokenRefresh = (callback: (token: string) => void) => {
13+
refreshSubscribers.push(callback);
14+
};
15+
16+
const onRefreshed = (token: string) => {
17+
refreshSubscribers.forEach(callback => {
18+
callback(token);
19+
});
20+
refreshSubscribers = [];
21+
};
1422

1523
axios.interceptors.response.use(
1624
(response: AxiosResponse) => response,
17-
async (error: AxiosError) => {
18-
const router = useRouter();
19-
const { login, logout, setAuthUserData } = useAuthActions();
25+
async (error: AxiosError<FailureDTO>) => {
26+
if (error.response?.status !== 401 || error.response?.data.code !== 'C002')
27+
return await Promise.reject(error);
2028

21-
const { config, response } = error;
22-
const originalRequest = config as AxiosRequestConfig;
23-
24-
const refreshToken = load<string>({
25-
type: 'local',
26-
key: 'refreshToken',
27-
});
29+
const refreshToken = load<string>({ type: 'local', key: 'refreshToken' });
30+
if (refreshToken == null) {
31+
window.location.href = '/';
32+
return await Promise.reject(error);
33+
}
2834

29-
if (
30-
response != null &&
31-
refreshToken != null &&
32-
response.status === 401 &&
33-
!isRefreshing
34-
) {
35-
isRefreshing = true;
35+
if (isRefreshing) {
36+
return await new Promise(resolve => {
37+
subscribeTokenRefresh((token: string) => {
38+
const { config } = error;
39+
if (config?.headers != null) {
40+
config.headers.Authorization = `Bearer ${token}`;
41+
resolve(axios(config));
42+
}
43+
});
44+
});
45+
}
3646

37-
return await new Promise((resolve, reject) => {
38-
postTokenRefresh(refreshToken)
39-
.then(({ data }) => {
40-
if (originalRequest.headers != null)
41-
originalRequest.headers.Authorization = `Bearer ${data.accessToken}`;
47+
isRefreshing = true;
48+
try {
49+
const {
50+
data: { accessToken, refreshToken: newRefreshToken, expiresIn },
51+
} = await postTokenRefresh(refreshToken);
4252

43-
login(data);
44-
getUserData()
45-
.then(({ data: user }) => {
46-
setAuthUserData(user);
47-
})
48-
.catch(err => {
49-
console.error(err);
50-
});
53+
axios.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
54+
save({ type: 'local', key: 'refreshToken', value: newRefreshToken });
55+
save({ type: 'local', key: 'expiresIn', value: `${expiresIn}` });
5156

52-
resolve(axios(originalRequest));
53-
})
54-
.catch(err => {
55-
router.push('/');
56-
logout();
57-
reject(err);
58-
})
59-
.finally(() => {
60-
isRefreshing = false;
61-
});
62-
});
57+
const { config } = error;
58+
onRefreshed(accessToken);
59+
if (config != null) {
60+
config.headers.Authorization = `Bearer ${accessToken}`;
61+
return await axios(config);
62+
}
63+
} catch (refreshError) {
64+
return await Promise.reject(error);
65+
} finally {
66+
isRefreshing = false;
6367
}
68+
6469
return await Promise.reject(error);
6570
},
6671
);

src/app/lib/providers/InitializationProvider.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export function InitialzationProvider({
1818
const { data: userData } = useUserData(auth?.accessToken != null);
1919

2020
useEffect(() => {
21-
console.log(userData);
2221
if (userData != null) {
2322
setAuthUserData(userData);
2423
if (userData.initialized) {

0 commit comments

Comments
 (0)