이번에는 로그인 기능이다. Device Life에서 로그인 기능은 사용자 인증 상태를 앱 전역에서 일관되게 유지하고, 인증이 필요한 페이지 및 기능에 대한 접근을 제어하는 기능이 메인 기능이다. 세부적인 기능 목록으로는 일반 로그인, 소셜 로그인(구글), 로그인 상태 유지, 토큰/세션 전략, 호출/응답 인터셉터 등이 있다.
초기에 로그인 기능을 구현할 때는 accessToken과 refreshToken 모두 localStorage에 저장하는 방식을 큰 틀로 선택하였다. 이렇게 선택한 이유는 내가 이 인증흐름에 대한 전문지식이 깊지 못했기에 우선은 제대로 작동하는 기능을 만들자는 생각이 앞서기도 하였고, 스웨거를 통해 api를 확인했을 때 두 종류의 토큰을 모두 JSON으로 함께 내려주는 응답 형태였기에 이 방식 밖에 떠오르지 않았던 거 같기도 하다. (추가로 소셜로그인과 로그인 상태 유지 기능은 나중에 나에게 맡기는 게으름을 피우기도 하였다;;;ㅋㅋ)
로그인 api연동만 잘하면 될 줄 알았으나 로그인은 생각보다 부수적으로 고려할 게 많은 기능이었다. 먼저 로그인 완료 시 내부적으로 우리 서비스가 어떤 상태여야 하나를 생각해봤을 때, 다양한 페이지에서 쓰이는 유저 프로필이 존재해야 하지 않나 싶었다. 이에 맞게 RootLayout에 유저정보를 자동로드하는 훅을 추가하였다. 추가로 로그인이 완료 시 처리되야 하는 로직이 회원가입과 같은 상황에서 재사용될 수 있겠다는 생각에 ‘로그인 api호출’ +‘토큰 저장’ + ‘유저 프로필 조회’ + ‘React Query 캐시 세팅’ 을 포함한 로그인 커스텀 훅을 하나 만들었다. 또한 호출/응답 인터셉터를 구현하였는데, 특히 응답 인터셉터의 경우 갱신 성공/실패로만 케이스를 나누었다가, 여러 요청이 동시에 401을 받는 경우가 꽤 많다는 말에 동시요청을 처리하는 로직도 추가하느라 골머리를 앓았던 거 같다…!