How I Smashed a Bug in a Shared Authentication Library
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. This happened a...
개요 #
풀스택 개발자 Daniel Balcarek이 대기업에서 겪은 버그 추적기를 Dev.to에 공개했다. 사용자가 브라우저 탭을 여러 개 열어두면 그중 한 탭에서 인증이 무작위로 끊겼고, 한번 끊긴 탭은 F5를 누르거나 닫기 전까지 복구되지 않았다.
원인은 사내 공유 인증 라이브러리에 있었다. 문제는 그 라이브러리를 만든 프론트엔드 팀과 인증 서비스를 운영하는 백엔드 팀이 서로 다른 조직이었다는 점이다. 두 팀 사이를 몇 주간 오간 끝에, 그는 라이브러리를 프로젝트에서 통째로 걷어내고 클라이언트 인증 플로우를 처음부터 다시 구현했다.
버그의 정체 #
Balcarek이 일하던 회사는 규모가 커서, 여러 팀이 함께 쓰는 라이브러리와 서비스를 전담 개발자들이 따로 유지보수했다. 그의 표현으로는 "사내 오픈소스"에 가까웠다. 당연히 그의 팀도 바퀴를 다시 발명하는 대신 그 라이브러리들을 가져다 썼다.
웹 애플리케이션 첫 버전을 배포하고 나서 문제가 드러났다. 여러 탭을 띄워놓으면 인증이 간헐적으로 깨졌다.
팀의 시니어 개발자였던 그가 이 버그를 맡았다. 한참을 파고든 끝에 확인한 사실은 이랬다. 프론트엔드가 인증 토큰을 갱신하려 할 때 403 Forbidden 응답이 돌아왔고, 그 순간 인증 플로우 전체가 무너졌다.
Chrome의 세션 스토리지와 로컬 스토리지를 이리저리 만져보고 인증 설정도 바꿔봤지만 별 소득이 없었다. 다만 한 가지는 분명해졌다. 버그는 공유 프론트엔드 인증 라이브러리 안에 있었다.
두 팀 사이를 오가다 #
그는 로그와 조사 결과를 모아 인증 라이브러리를 담당하는 프론트엔드 팀을 찾아갔다. 한 시간 넘게 논의한 끝에 프론트엔드 팀이 내놓은 결론은 "우리 잘못이 아니다"였다. 애초에 백엔드 인증 서비스가 그런 응답 코드를 돌려주면 안 된다는 것이다.
납득이 되진 않았지만, 저쪽 인원이 더 많았다.
이번엔 로그를 다시 챙겨 백엔드 팀으로 갔다. 여기서 진짜 원인이 나왔다. 백엔드가 돌려준 응답 코드는 정상이었다. 프론트엔드 인증 라이브러리가 이미 무효화된 리프레시 토큰을 보내고 있었기 때문이다. 근본 원인은 탭 간 경쟁 상태(race condition)였다. 한 탭이 토큰을 갱신하면서 이전 리프레시 토큰을 무효화했는데, 다른 탭은 여전히 그 토큰을 쓰려 하고 있었다.
두 팀이 왜 직접 대화하지 않았는지 궁금하다면, 양쪽 모두 그에게 거의 같은 답을 줬다고 한다.
이건 당신들 애플리케이션 문제니까, 당신 팀이 해결해야 한다.
티켓, 회의, 그리고 결렬 #
다시 프론트엔드 팀으로 돌아가 백엔드 팀의 결론을 전달했지만 여전히 받아들여지지 않았다. 슬슬 화가 난 그는 티켓 하나를 만들어 두 팀을 모두 참조에 넣고, 그동안 모은 로그와 요청·응답·타임스탬프를 전부 첨부했다.
그렇게 몇 주가 흘렀다. 티켓과 채팅에서 대화는 이어졌지만 해결은 요원했다.
결국 관계자 전원을 모아 회의를 잡았다. 그제야 진전이 있었다. 문제는 프론트엔드 인증 라이브러리에 있고, 프론트엔드 팀이 고치기로 합의했다.
해결된 줄 알았다.
2주 뒤, 테스터와 사용자들의 불만이 쌓여가던 시점에 프론트엔드 팀이 내놓은 최종 결론은 두 문장이었다.
재현할 수 없었다.
그리고 사용자는 여러 탭으로 애플리케이션을 열면 안 된다.
그때까지 멀티탭 사용은 지극히 평범한 사용자 플로우로 여겨지던 동작이었다.
라이브러리를 걷어내다 #
Balcarek은 티켓을 닫았다. 그리고 사내 프론트엔드 인증 라이브러리를 프로젝트에서 완전히 제거한 뒤, 기존 사내 인증 서비스를 상대로 클라이언트 인증 플로우를 직접 다시 구현했다.
주요 변경은 Angular HTTP 인터셉터와 토큰 갱신 플로우 두 곳이었다. 인터셉터는 403 Forbidden을 포함한 인증 관련 응답을 처리하도록 손봐서, 탭 전체가 망가진 상태로 멈춰버리지 않게 만들었다. 갱신된 토큰을 다루고 세션 스토리지에 저장하는 방식도 새로 짰다. 무효화된 토큰과 갱신 실패를 명시적으로 처리해서, 인증 플로우가 아예 멈추는 일이 없도록 했다.
작업에는 이틀과 하룻밤이 들었다. 사내 인증 라이브러리에서 아이디어 몇 개를 가져다 쓴 덕에 그 정도로 끝났다고 그는 덧붙였다.
그 뒤로는 문제없이 돌아갔다. 새 버그가 나와도 즉시 고칠 수 있었다. 이번엔 코드를 직접 소유하고 있었으니까.
이 글은 위 출처를 바탕으로 한국 독자를 위해 재작성한 기사입니다. 원문의 사실과 수치에 근거하며, 별도의 견해를 포함하지 않습니다.

