interceptors란 axios 요청 또는 응답을 가로채어 추가적인 동작을 진행할 수 있는 기능이다.
이것을 통해 JWT의 RefreshToken을 적용하고 구현해봤다.
아래는 예전에 프로젝트를 진행하며 작성했던 코드다.
instance.interceptors.response.use((res) => {
return res;
}, (err) => {
if(err.response && err.response.status === 401) {
const refreshToken = sessionStorage.getItem("Refresh__Token");
const prevAccessToken = sessionStorage.getItem("Authorization");
const originRequest = err.config; // 원래의 요청
return axios.put(`${process.env.REACT_APP_API_URL}/api/refreshToken`,{}, {
headers: {
Authorization:prevAccessToken,
RefreshToken:refreshToken
}
}).then((res) => {
const newAccessToken = res.headers.authorization;
sessionStorage.setItem("Authorization", newAccessToken);
originRequest.headers.Authorization= newAccessToken;
return instance.request(originRequest).catch((e) => {
alert("세션이 만료되었습니다.");
console.log(e);
window.location.href="/login";
}); // 원래의 요청으로 다시 요청
}).catch((err) => {
alert("세션이 만료되었습니다.")
sessionStorage.removeItem("Authorization");
window.location.href="/login";
})
}
}
return Promise.reject(err.config);
)
기본적으로 JWT를 이용하여 토큰 기반 인증 방식을 사용하기 위해서는 인증이 필요한 모든 API 요청에 AccessToken
을 header에 포함시켜야한다.
클라이언트에서 사용자의 AccessToken을 가지고 있고, 이를 요청의 headers에 포함하여 정상적으로 요청을 했을 때,
만약 요청에 포함되었던 토큰이(클라이언트가 가지고 있었던 토큰이) 만료되었다면 요청은 당연히 거부되어야 할 것이다. 그리고 거부 된 것을 응답을 통해 알려주게 된다.
그렇기 때문에 interceptors를 사용하여 응답을 가로채고, 에러가 발생했다면, RefreshToken을 사용하여 새로운 AccessToken을 받아오는 API 요청을 하여 AccessToken을 갱신하고, 기존에 토큰이 만료되어 거부되었던 요청을 새로운 AccessToken을 사용하여 다시 요청하는 방식이다.
다시 요청하는 이유는 개발 의도에 따라 다르지만, 나는 사용자가 자신의 로그인 상태가 만료되었는지 모르고 자연스럽게 사용할 수 있게 하는 것이 개발하고 있던 웹 어플리케이션에 더 잘 맞다고 생각했고, 사용자 경험 측면에서도 더 좋을 것이라고 판단하였다.
코드에서는 const originRequest = err.config
을 통해 거부되었던 원래의 요청을 따로 저장하고, AccessToken을 갱신하는 과정을 거친 후, 기존의 요청을 재요청하는 것을 알 수 있다.
return instance.request(originRequest).catch((e) => {
alert("세션이 만료되었습니다.");
console.log(e);
window.location.href="/login";
}); // 원래의 요청으로 다시 요청