React 로그인(자동로그인) 처리 / silent refresh

김정민·2023년 10월 9일
1

interceptor를 이용한 Access Token 유지

현재 프로젝트에서 Access Token 만료로 인한 UnAuthorization 에러코드에 대응하기 위해 interceptor 단에서 미리 지정해놓은 에러코드일 경우 재발급 후 다시 재요청을 진행하는 코드를 작성하였다.

if (response?.data.status.code === 1204) {
      await reTakeToken();

      return api(config);
}

해당 api 가 Access Token을 재발급하더라도 에러가 있다면 재귀적으로 호출이 될 수 있다.

if (response?.data.status.code === 1204) {
      await reTakeToken();

      return axios(config);   <-- 인스턴스가 아닌 axios로 변환
}

이렇게 기존 인스턴스대신 axios로 변환하여 작성하였다.

하지만 또 이렇게 코드를 짜면 if (서버에러)일 때 retake토큰에 대한 무한재귀가 일어난다….

if (response?.data.status.code === 1204) {
      await reTakeToken();   <-- 예기치못한 서버에러일 때 무한 재귀가 일어난다
			// 물론 instance가 아닌 별도에 axios나 fetch로 시도하면 대응할 수 있다.

      return axios(config);   
}

reTakeToken api를 기존 instance가 아닌 다른 방식으로 request를 보내면 대응이 되지만,

프로젝트에서는 임의의 변수를 하나 생성해서


let count = 0;

interceptor {
	count += 1;

    /**
     * 서버 오류 시 무한 재귀를 대응하기위한 if문
     */
    if (count > 3) {
      count = 0;
      return Promise.reject(error);
    }
}

무한으로 재귀가 일어나는 것을 막아주었다.

고민했던 점.

React Query를 사용하고 있는데, 해당 interceptor 내에 코드로 인하여 onSuccess onError처리에 있어서 충돌이 있지않을까? 생각을 하였다

애초에 interceptor라서 해당 요청에 response를 보내기전에 가로채서 진행하는 거긴 때문에 React Query 단을 걱정할 필요는 없었다.

React query는 mutationFn queryFn이 프로미스를 최종으로 resolve했는지 reject했는지만을 보고 Next step을 결정하는 구조이다.

Polling (silent refresh)추가

하지만 이렇게 interceptor → error 쪽에 코드가 추가되다 보니깐
해당 401에러가 발생했을 때 꽤나 요청이 느려지는 것을 확인할 수 있었다.

임시로 테스트를 해보기위해 error를 강제로 throw 후 해당 code를 임의로 추가하였다

interceptor{
	await reTakeToken();
	
	return api({ ...config, url: '/api/event/penalty/77' }); 
	// 강제로 잘못된 요청을 보내고 제대로된 요청으로 수정해주었다.
}

interceptor에서 reTakeToken을 실행 시

화살표가 가르치듯 저렇게 error response가 왔을 때 reTakeToken(refresh)을 받는 과정에 !!대략500~600ms!! 시간이 추가로 소요된다는 것을 확인하였다.

이런 과정을 그나마 최소화 하기위해서 polling 형태로 지속적인 reTakeToken으로 Access Token을 재발급 해주는 Query와 Provider를 추가해주었다.

0개의 댓글