Axios Interceptor (엑시오스 인터셉터)를 사용하여 Access Token 재발급(갱신)
Axios Interceptor (엑시오스 인터셉터)
(https://axios-http.com/kr/docs/interceptors)

Axios 요청 전이나 Axios 응답 후 처리는 Axios Interceptor (엑시오스 인터셉터)을 사용하여 가로챌 수 있습니다.
Axios Interceptor (엑시오스 인터셉터) 기본 구조입니다.
// 요청 인터셉터
axios.interceptors.request.use(function (config) {
// Do something before request is sent
// 요청이 전달되기 전에 처리
return config;
}, function (error) {
// Do something with request error
// 요청 오류에 대한 처리
return Promise.reject(error);
});
// 응답 인터셉터
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// 응답 상태코드가 2xx 범위안에 있으면 트리거됩니다.
// Do something with response data
// 응답 데이터로 처리
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// 응답 상태코드가 2xx 범위를 벗어나면 트리거됩니다.
// Do something with response error
// 응답 오류에 대한 처리
return Promise.reject(error);
});
1. src에 apis 디렉터리를 생성하고 axiosInterceptor.js 파일을 생성합니다.

import axios from 'axios';
const axiosInstance = axios.create();
// 요청 인터셉터
axiosInstance.interceptors.request.use(function (config) {
console.log("axios.interceptors.request");
return config;
}, function (error) {
console.log("axios.interceptors.request.error");
console.log(error);
return Promise.reject(error);
});
// 응답 인터셉터
axiosInstance.interceptors.response.use(function (response) {
console.log("axios.interceptors.response");
return response;
}, function (error) {
console.log("axios.interceptors.response.error");
console.log(error);
return Promise.reject(error);
});
export default axiosInstance;
2. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list)

3. src\apis\axiosInterceptor.js 파일을 수정합니다.
import axios from 'axios';
import { useLoginStore } from '@/stores/useLoginStore';
export const createAxiosInstance = () => {
const loginStore = useLoginStore();
const axiosInstance = axios.create();
// 요청 인터셉터
axiosInstance.interceptors.request.use(async function (config) {
console.log("axios.interceptors.request");
console.log(loginStore.access_token);
return config;
}, function (error) {
console.log("axios.interceptors.request.error");
console.log(error);
return Promise.reject(error);
});
// 응답 인터셉터
axiosInstance.interceptors.response.use(function (response) {
console.log("axios.interceptors.response");
return response;
}, function (error) {
console.log("axios.interceptors.response.error");
console.log(error);
return Promise.reject(error);
});
return axiosInstance;
};
Store를 사용하기 위해서 함수로 변경해야 합니다.
4. src\views\LunchMenu\LunchMenuListView.vue 파일을 수정합니다.
<script>
:
//import axios from 'axios';
import { createAxiosInstance } from '@/apis/axiosInterceptor';
:
export default {
name : 'LunchMenuListView',
setup() {
const router = useRouter();
const route = useRoute();
:
async function getLunchMenuList() {
console.log(loginStore.access_token);
:
try {
const res = await createAxiosInstance().get("http://127.0.0.1:9000/api/v1/lunchmenus/", {
headers: {
"Authorization" : "Bearer " + loginStore.access_token
}
});
console.log(res);
lunchMenuList.value = res.data.data;
} catch(err) {
console.log(err);
}
:
5. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list)

Axios Interceptor (엑시오스 인터셉터) 사용 - Axios 요청 전 적용
Access Token의 만료 확인 시점
요청하기 전에 Access Token이 만료되었는지 확인하기 위해서는 Axios Interceptor (엑시오스 인터셉터)을 사용합니다.
Access Token의 payload에 있는 exp(expiration, 만료 시간)를 확인하여 만료되었는지 확인 후 Refresh Token를 사용하여 Access Token를 재발급합니다. → 매번 Access Token를 확인

1. src\apis\axiosInterceptor.js 파일을 수정합니다.
:
import { useRouter } from 'vue-router';
export const createAxiosInstance = () => {
:
const router = useRouter();
:
// 요청 인터셉터
axiosInstance.interceptors.request.use(async function (config) {
console.log("axios.interceptors.request");
console.log(loginStore.access_token);
if (loginStore.isAccessTokenExpire()) {
console.log("Access Token이 만료되었습니다.");
try {
await loginStore.doRefreshToken();
} catch(err) {
console.log(err);
alert("인증이 만료되었습니다.\n다시 로그인 해주시기 바랍니다.");
router.replace({name : 'Login'});
}
}
return config;
}, function (error) {
console.log("axios.interceptors.request.error");
console.log(error);
return Promise.reject(error);
});
:
2. src\views\LunchMenu\LunchMenuListView.vue 파일을 수정합니다.
<script>
:
import { useRouter } from 'vue-router';
:
export default {
name : 'LunchMenuListView',
setup() {
:
// const route = useRoute();
:
async function getLunchMenuList() {
console.log(loginStore.access_token);
/*
if (loginStore.isAccessTokenExpire()) {
console.log("Access Token이 만료되었습니다.");
try {
await loginStore.doRefreshToken();
} catch(err) {
console.log(err);
alert("인증이 만료되었습니다.\n다시 로그인 해주시기 바랍니다.");
router.replace({path: '/login', query: { returnUrl: route.fullPath }});
return;
}
}
*/
:
useRoute를 삭제하고 Access Token 만료 처리를 부분을 주석처리하거나 삭제합니다.
3. src\views\Account\LoginView.vue 파일을 수정합니다.
<script>
:
export default {
name : 'LoginView',
setup() {
:
function loginClick() {
:
const memberInfo = { id: state.memberId, password: state.memberPassword };
loginStore.doLogin(memberInfo).then(() => {
const returnUrl = route.query.returnUrl;
if (returnUrl == null || returnUrl == "") {
router.replace({name : 'home'});
} else {
router.replace({path : returnUrl});
}
}).catch((err) => {
state.errorMessage = err.message;
});
}
:
returnUrl이 없으면 홈으로 이동되게 처리합니다.
4. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list) → Access Token 만료 (10분 후) → Access Token 재발급(갱신)

5. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list) → Access Token 만료 (15분 후) → Refresh Token 만료 → 재발급(갱신) 불가 → 로그인 → 홈

Axios Interceptor (엑시오스 인터셉터) 사용 - Axios 응답 후 적용
Access Token의 만료 확인 시점
요청 후 응답에서 Access Token이 만료되었는지 확인하기 위해서는 Axios Interceptor (엑시오스 인터셉터)을 사용합니다.
요청 후 응답에서 Access Token이 만료되었다는 응답 코드(401, Unauthorized)와 응답 메시지(“토큰이 만료되었습니다.”)가 오면 Refresh Token를 사용하여 Access Token를 재발급하고 다시 요청을 보냅니다. → 요청에 대한 응답이 실패일 경우만 처리

1. src\apis\axiosInterceptor.js 파일을 수정합니다.
:
export const createAxiosInstance = () => {
:
// 요청 인터셉터
axiosInstance.interceptors.request.use(async function (config) {
console.log("axios.interceptors.request");
console.log(loginStore.access_token);
config.headers['Content-Type'] = 'application/json';
config.headers['Authorization'] = `Bearer ${loginStore.access_token}`;
/*
if (loginStore.isAccessTokenExpire()) {
console.log("Access Token이 만료되었습니다.");
try {
await loginStore.doRefreshToken();
} catch(err) {
console.log(err);
alert("인증이 만료되었습니다.\n다시 로그인 해주시기 바랍니다.");
router.replace({name : 'Login'});
}
}
*/
return config;
}, function (error) {
:
Request Header에 Authorization를 추가하고 Access Token 만료 처리 부분을 주석처리하거나 삭제합니다.
2. src\views\LunchMenu\LunchMenuListView.vue 파일을 수정합니다.
<script>
:
//import { useLoginStore } from '@/stores/useLoginStore';
:
export default {
name : 'LunchMenuListView',
setup() {
:
//const loginStore = useLoginStore();
:
async function getLunchMenuList() {
//console.log(loginStore.access_token);
try {
/*
const res = await createAxiosInstance().get("http://127.0.0.1:9000/api/v1/lunchmenus/", {
headers: {
"Authorization" : "Bearer " + loginStore.access_token
}
});
*/
const res = await createAxiosInstance().get("http://127.0.0.1:9000/api/v1/lunchmenus/");
console.log(res);
lunchMenuList.value = res.data.data;
} catch(err) {
console.log(err);
}
}
:
Header를 삭제합니다.
3. src\apis\axiosInterceptor.js 파일을 수정합니다.
:
export const createAxiosInstance = () => {
:
// 응답 인터셉터
axiosInstance.interceptors.response.use(function (response) {
console.log("axios.interceptors.response");
return response;
}, async function (error) {
console.log("axios.interceptors.response.error");
console.log(error);
var axiosRequest = error.config;
if (error.response && !axiosRequest._retry) {
axiosRequest._retry = true;
// 응답코드가 401이면 처리합니다.
if (error.response.status == 401) {
if (loginStore.isAccessTokenExpire()) {
console.log("Access Token이 만료되었습니다.");
try {
// Access Token 재발급 요청
await loginStore.doRefreshToken();
// 재발급된 Access Token으로 header를 수정합니다.
axiosRequest.headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${loginStore.access_token}`
};
// 다시 요청(request)합니다.
const response = await axios.request(axiosRequest);
return response;
} catch(err) {
console.log(err);
alert("인증이 만료되었습니다.\n다시 로그인 해주시기 바랍니다.");
router.replace({name : 'Login'});
}
}
}
}
return Promise.reject(error);
});
:
재요청이 실패하면 계속 반복되기 때문에 반복을 방지하기 위해서 요청 정보(config)에 _retry를 사용하여 한 번만 처리되게 합니다.
응답 상태코드가 401이고 Access Token 만료되어 있으면 Access Token를 재발급하고 요청 정보(config)를 사용하여 다시 요청합니다.
4. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list) → Access Token 만료 (10분 후) → Access Token 재발급(갱신)

5. 웹 브라우저에서 확인하기 (http://localhost:8080/lunchmenu/list) → Access Token 만료 (15분 후) → Refresh Token 만료 → 재발급(갱신) 불가 → 로그인 → 홈

'Vue.js 3 & NodeJS > 사내교육 - 점심 메뉴' 카테고리의 다른 글
| [17] Frontend 개발 - Store State 유지, Cookies, localStorage, Pinia Plugin Persistedstate (0) | 2026.08.05 |
|---|---|
| [17] Frontend 개발 - Login 관리, 모듈화 (0) | 2026.08.05 |
| [15] Frontend 개발 - Login 관리, Access Token, Refresh Token (0) | 2026.08.05 |
| [14] Backend 개발 - 사용자 API 개발, 라우트 별 인증 처리, 인가 처리 (0) | 2026.08.05 |
| [13] Backend 개발 - 사용자 API 개발, Access Token, Refresh Token (0) | 2026.08.05 |