인증을 붙이다 만난 무 한 리다이렉트 루프
로그인 한 번 붙이는 일이 왜 무한 리다이렉트 루프로 이어졌는지, 그리고 쿠키 크기 한계가 설계를 어떻게 바꿨는지 정리합니다.
지난 편에서 서비스를 여러 개로 나눈 이야기를 했습니다. 서비스가 나뉘면 화면(프론트엔드)도 여러 곳에 흩어집니다. 제품 사이트가 따로 있고, 로그인을 전담하는 인증 사이트가 따로 있습니다. 그러면 "한 곳에서 로그인하면 다른 곳에서도 로그인 상태가 유지되어야 한다"는 문제가 생깁니다.
이 문제를 풀다가 무한 리다이렉트 루프에 빠졌습니다. 그 과정을 적어 봅니다.
왜 인증 사이트를 따로 두었나
로그인 화면을 제품마다 만들면, 제품이 늘어날 때마다 로그인 코드도 복제됩니다. 그래서 로그인은 인증 사이트 한 곳에서만 처리하기로 했습니다.

제품은 여러 동(棟)으로 나뉜 건물이고, 출입증을 발급하는 곳은 별도의 안내 데스크 한 곳입니다. 어느 동에 들어가려 하든, 출입증이 없으면 먼 저 안내 데스크로 보냅니다. 거기서 신원을 확인하고 출입증을 받아 다시 원래 동으로 돌아옵니다.
흐름은 이렇게 됩니다.
- 사용자가 제품 사이트에서 로그인을 누릅니다.
- 인증 사이트로 보냅니다. 이때 "끝나면 어디로 돌아갈지"(
return_to)를 함께 넘깁니다. - 인증 사이트에서 신원을 확인합니다.
- 토큰을 그대로 넘기면 위험하니, 토큰을 암호화한 짧은 코드를 만들어 제품 사이트로 돌려보냅니다.
- 제품 사이트가 그 코드를 토큰으로 교환합니다(exchange).
- 토큰을 저장하고, 원래 보려던 화면으로 돌아갑니다.
이 방식을 BFF(Backend for Frontend) 패턴이라고 부릅니다. 토큰 자체를 주소창에 노출하지 않고, 한 단계 안전하게 교환하는 구조입니다.
그런데 회전문에 갇혔습니다
문제가 생겼습니다. 로그인을 누르면 인증 사이트로 갔다가, 다시 제품 사이트로 왔다가, 또 인증 사이트로 가기를 끝없이 반복했습니다. 회전문에 갇힌 것처럼 같은 자리를 빙빙 돌았습니다.

원인을 파보니 한 가지가 아니라 세 가지가 겹쳐 있었습니다.
원인 1. 돌아갈 주소를 잃어버렸다
"끝나면 어디로 돌아갈지"(return_to)를 임시 저장소(sessionStorage)에 담아 두었습니다. 그런데 로그인이 한 번 실패하고 재시도하는 사이 이 저장소가 비워졌습니다. 돌아갈 주소를 잃으니, 인증이 끝나도 제품 사이트로 못 가고 인증 사이트 안에서만 맴돌았습니다.
안내 데스크에 "저는 3동에서 왔어요"라고 적은 메모를 맡겼는데, 그 메모가 중간에 사라졌습니다. 출입증은 받았지만 어느 동으로 가야 할지 모르게 된 것이지요.
원인 2. 출입증이 주머니에 안 들어갔다
이게 가장 찾기 어려웠습니다. 토큰을 쿠키에 저장하려 했는데, 쿠키 하나의 크기 한계는 약 4KB(4096바이트)입니다.
그런데 우리가 담아야 할 토큰은 두 종류였습니다.
- 신원 토큰(id token): 약 1,500바이트
- 갱신 토큰(refresh token): 약 1,700바이트
두 개만 해도 3,200바이트입니다. 여기에 토큰을 암호화하면 크기가 더 늘어납니다(암호화와 인코딩을 거치면 대략 1.3배). 쿠키에 붙는 부가 정보까지 더하니 4,096바이트를 넘어 버렸습니다.
브라우저는 이때 아무 오류도 내지 않고 조용히 쿠키를 버립니다. 저장된 줄 알았는데 실제로는 비어 있었습니다. 그러니 다음 요청에서 "인증 안 됨"으로 막히고, 다시 로그인 화면으로 돌아갑니다. 회전문의 진짜 동력이 여기 있었습니다.
출입증을 주머니에 넣었다고 생각했는데, 주머니가 작아서 출입증이 바닥에 떨어졌습니다. 본인은 가진 줄 알고 다음 문에 갔다가 "출입증 없으시네요" 하고 다시 안내 데스크로 돌아가기를 반복합니다.