FE 개발자의 모노레포 도입기...

토큰을 곁들인...
윤여찬's avatar
Jan 17, 2026
FE 개발자의 모노레포 도입기...

모노레포를 선택한 이유: JWT 인증 구조를 재정의하고 공통화하다

여러 개의 프론트엔드 프로젝트를 동시에 운영하면서 가장 크게 드러난 문제는 인증 구조의 불안정성과 프로젝트 간 파편화였습니다. 실제로 사용하는 프로젝트는 4개, 더 점진적으로 기능은 늘어갈 것이 확고했고 R&D의 기회가 있어 방향성을 정하는게 가장 중요하다고 생각했다.
 
표면적으로는 같은 UI와 유사한 기능을 사용하고 있었지만, 내부적으로는 토큰 관리 방식과 인증 흐름이 제각각이었고 이는 곧 보안 취약성과 사용자 경험 저하로 이어져있음을 확인했습니다. 이러면 제가 프론트 엔지니어로 살아가기로 마음먹은 이례로 바꾸지 않곤 잠이 안올듯했고 바꾸기로 결심하고 일단 토큰부터 손보기 시작했습니다.
 
토큰을 수정한 후 4개의 프로젝트를 각기 같은 방식으로 정리하는게 정답이 아니라는 생각이 지배적이었고 이 문제를 해결하기 위해 단순한 리팩터링이 아닌,
모노레포 기반의 인증·UI 아키텍처 재설계를 선택했습니다.

기존 구조에서 드러난 핵심 문제

1. JWT 사용은 하고 있었지만, 구조적으로 안전하지 않았다

이전에도 JWT 기반 인증을 사용하고 있었지만, 실제 운영 환경에서는 다음과 같은 문제가 반복적으로 발생했습니다.
  • Access Token / Refresh Token이 JS에서 접근 가능한 영역에 존재
    • 이렇게 되면 아무리 엑세스토큰이 1시간 단위의 만료 시간이 있더라도 리플래시가 7일 동안은 유효하니 계속해서 연장할 수 있다는 것… 결국 리플래시가 접근 가능하다는건 보안의 취약점이 크게 존재한다는 점이 마음에 걸렸다.
  • 토큰 만료 시점과 인증 상태가 어긋나며 강제 로그아웃 또는 화면 튕김 발생
    • 엑세스 토큰 재발급 과정에서 이전 개발자가 작업해논 부분에 코드가 제대로 실행되지 않는 것을 확인 이로 인해 문제가 발생함에 수정을 진행…
  • 프로젝트마다 토큰 저장 위치·갱신 방식이 달라 예외 케이스 증가
    • 수정 후 R&D는 최신화 된 XSS 공격에 취약하지 않은 상태가 되었고 실제로 리플래시 토큰엔 접근 조차 못하는 상태이지만 기존 프로젝트 3개는 보안이 아직 취약한 상황…
  • XSS 공격에 취약한 구조
  • 미들웨어를 사용하지 않는 구조
즉, JWT를 사용하고는 있었지만 “어디에, 어떻게 보관하고, 어떤 흐름으로 갱신할 것인가”에 대한 설계가 프로젝트 단위로 흩어져 있던 상태였습니다.

2. 프로젝트별 인증 로직의 중복과 비일관성

  • 3개의 프로젝트에서 거의 동일한 로그인 / 토큰 갱신 코드
  • UI는 비슷하지만 컴포넌트 구현은 각자 관리
    • 이렇게 되면 공통 되는 부분은 계속 늘어가 관리 포인트가 늘어간다는 점… 더군다나 인수인계가 불확실한 상황이라면 내부 회사에서도 취약점이 크게 늘어가는 구조였다.
    • 실제로 이전 회사에서 누군가가 개발한 리포지토리는 그냥 묻혀서 묵은지 처럼 땅속에 뭍혀 버리는 상황이 잦았다.
  • 인증 정책 변경 시 모든 프로젝트를 동시에 수정해야 하는 구조
이 구조는 단기적으로는 빠를 수 있었지만,
중장기적으로는 유지보수 불가능한 상태에 가까워지고 있었습니다.

사전에 정리한 JWT 인증 설계

모노레포 전환 이전, JWT 인증 구조에 대해 별도로 정리·설계한 문서가 있었습니다.
해당 문서에서는 다음과 같은 방향성을 명확히 정의해두었습니다.
  • Access Token과 Refresh Token의 역할 분리
  • 토큰 수명과 갱신 타이밍에 대한 기준
  • 클라이언트가 토큰을 “보관”하지 않고 “사용만” 하도록 만드는 구조
  • 서버 주도 인증 흐름
이 설계의 핵심은 단순히 JWT를 발급하는 것이 아니라,
브라우저 환경에서 가장 안전하게 운용할 수 있는 방식으로 JWT를 다루는 것이었습니다.
이 사전 설계를 바탕으로, 실제 운영 환경에 맞게 구조를 고도화하며 공통 인증 패키지로 구현하게 됩니다.

핵심 전환: HttpOnly + Refresh Token 은닉

 

1. HttpOnly 기반 인증 구조

기존 JWT 설계를 실제 서비스에 적용하며 다음과 같이 구조를 전환했습니다.
  • Refresh Token은 HttpOnly Cookie에 저장
  • Access Token은 클라이언트 메모리 기반 관리
  • SameSite 정책은 Lax로 설정
    • CSRF 리스크를 최소화
    • 온프레미스(B2B) 환경에서도 안정적으로 동작하도록함
이 방식으로 얻은 효과
  • JS에서 Refresh Token 접근 불가 → XSS 공격 대응
  • 토큰 만료 시 서버 주도 재발급(SSR의 장점) → 로그인 튕김 현상 제거
  • 인증 흐름의 단일화 및 예측 가능성 확보

2. 토큰 갱신 흐름의 명확한 분리

  • 인증이 필요한 요청 → Access Token 사용
  • 만료 시 → Refresh Token 기반 재발급
  • 중복 재발급 방지를 위한 쿨다운 로직 적용
이 흐름을 하나의 공통 인증 모듈로 캡슐화함으로써,
각 프로젝트에서는 인증 구현을 신경 쓰지 않아도 되는 구조를 만들었습니다.

모노레포로의 확장: 인증과 UI의 공통화

1. 인증 로직의 완전한 공용 패키지화

모노레포 내에 인증 전용 패키지를 구성하고 다음을 모두 통합했습니다.
  • JWT 발급·갱신 흐름
  • 인증 상태 관리
  • API 요청 시 인증 헤더 처리
  • 에러 및 만료 처리 정책
이제 인증 정책이 변경되면,
하나의 패키지 수정으로 모든 프로젝트에 즉시 반영됩니다.

2. UI와 디자인 토큰의 통합

인증 구조와 함께 UI도 공통화했습니다.
  • 버튼, 입력 컴포넌트, 레이아웃
  • 인증 관련 UX 패턴
  • 디자인 토큰 단일 관리
이는 단순한 코드 재사용이 아니라,
  • 서비스 전반의 UI 일관성 확보
  • 유지보수 비용 감소
  • 신규 프로젝트 확장 시 즉시 적용 가능한 기반 마련
이라는 구조적 이점을 가져왔습니다.

“JWT를 쓴다”에서 “JWT를 제대로 운용한다”로 변환

이번 모노레포 전환은 단순한 저장소 통합이 아니었다…
  • 사전에 설계한 JWT 인증 전략을 실제 서비스 구조로 구현하였고
  • 보안에 취약했던 토큰 관리 방식 제거하며 보안에 신경을 썻다.
  • 인증과 UI를 프로젝트 단위가 아닌 플랫폼 단위로 관리하며 추후 관리 포인트를 두었다.
특히 온프레미스 환경이라는 제약 속에서, 프론트엔드 단에서 할 수 있는 가장 현실적이고 안정적인 인증 구조를 만들었다고 판단하는데 5년차 개발자라 다른 방법이 있을 수 있다고 생각한다… 그점은 더 발전할 가능성이 있다고 생각하여 더 자주 보며 바꿀 예정이다.
이제 각 프로젝트는 인증 구현에 대한 고민 없이비즈니스 로직과 사용자 경험에만 집중할 수 있는 구조가 되었다…

왜 “모노레포”였는가: 다른 선택지들과의 비교

JWT 인증 구조를 재정의하면서 자연스럽게 마주한 질문은 하나였습니다.
“이 인증 구조를 앞으로 어디에서, 어떻게, 얼마나 오래 유지할 것인가”
단일 프로젝트 기준으로 보면
각 프로젝트에 동일한 인증 로직을 복사해서 유지하는 것도 선택지일 수 있습니다.
하지만 실제 상황은 달랐습니다.
  • 이미 운영 중인 프론트엔드 프로젝트 4개
  • R&D 성격의 신규 프로젝트 지속 추가 예정
  • 온프레미스 환경 + 고객사 사이트별 커스터마이징 가능성
  • 인수인계 리스크가 높은 조직 구조
이 조건에서 프로젝트 단위 관리는 곧 기술 부채의 누적으로 이어질 수밖에 없었습니다.

고려했던 다른 방식들

1. 인증 로직을 각 프로젝트에 유지 + 문서화

  • 장점: 초기 비용 최소
  • 단점:
    • 문서와 실제 코드 간 괴리 발생
    • 긴급 수정 시 모든 프로젝트 동시 수정 필요
    • “지켜야 하는 규칙”은 결국 지켜지지 않음

2. 인증만 별도 레포지토리로 분리 (submodule)

  • 장점: 코드 중복 감소
  • 단점:
    • 서브모듈 관리 비용
    • 로컬 개발 환경 구성 난이도 상승
    • 타입 공유 및 즉각적인 반영이 어려움

3. 모노레포 기반 공통 패키지화 (선택)

  • 인증·UI·API 호출을 패키지 단위로 추상화
  • 프로젝트는 이를 “사용”만 함
  • 수정 포인트를 구조적으로 제한
결국 선택 기준은 명확했습니다.
“사람이 지키는 규칙”이 아니라, 구조적으로 지킬 수밖에 없는 설계”
이게 중요한건 이전 회사에서 진짜 오랜 프로젝트는 관리도 안되고 ui는 같고 관리포인트가 잡히지도 않았던 경험이 한몫했습니다.

프론트엔드에서 보안을 다룬다는 것의 의미

프론트엔드 5년차 개발자로서 “보안”을 이야기하면 종종 이런 반응을 마주합니다.
  • “그건 백엔드에서 처리해야 하는 거 아닌가요?”
  • “프론트에서 할 수 있는 게 있나요?”
하지만 이번 작업을 통해 확신하게 된 점이 있습니다.

프론트엔드는 보안을 ‘완성’하지는 못해도, ‘무너뜨릴 수는 있다’

  • Refresh Token을 JS에서 접근 가능하게 두는 순간
  • 토큰 갱신 흐름이 예외 케이스를 허용하는 순간
  • 인증 상태와 UI 상태가 분리되는 순간
그 어떤 강력한 서버 보안도 클라이언트에서 무력화될 수 있습니다.
그래서 이번 구조에서는 프론트엔드의 역할을 명확히 정의했습니다.
  • 토큰을 보관하지 않는다
  • 인증 흐름을 직접 제어하지 않는다
  • 실패 케이스를 예측 가능한 흐름으로 한정한다.
프론트엔드는 “보안을 구현하는 주체”가 아니라 보안을 훼손하지 않는 구조를 유지하는 역할에 집중하도록 했습니다.

모노레포 전환 이후, 달라진 개발자의 사고 방식

기술적으로 가장 큰 변화는 코드 구조였지만, 체감상 더 큰 변화는 개발자의 사고 방식이었습니다.

이전

  • “이 프로젝트에서는 이렇게 처리하자”
  • “일단 여기만 고치자”
  • “다른 프로젝트는 나중에…”

이후

  • “이 기능은 패키지로 분리해야 하는가?”
  • “이 로직은 플랫폼 관점에서 봤을 때 어디에 있어야 하는가?”
  • “이 변경이 모든 프로젝트에 동시에 적용되어도 안전한가?”
모든 결정을 프로젝트 단위가 아닌 플랫폼 단위로 하게 되었고, 그 자체로 코드 품질과 안정성이 한 단계 올라갔다고 느꼈습니다.

이 구조가 의미 있는 이유

이 모노레포 구조는 “완벽한 정답”은 아닙니다.
앞으로도 수정될 것이고, 더 나은 방식이 나올 수도 있습니다.
다만 지금 시점에서 확실한 것은,
  • JWT 인증을 제대로 설계하고
  • 그 설계를 구조적으로 강제하고
  • 여러 프로젝트가 같은 기준 위에서 함께 발전할 수 있는 토대를 만들었다는 점입니다.
이제 새로운 프로젝트를 시작할 때 저는 이렇게 말할 수 있습니다.
“인증은 이미 준비되어 있습니다. 우리는 이제 서비스에만 집중하면 됩니다.”

다음에 다룰 이야기

이 글에서는 왜 모노레포를 선택했는지, 그리고 JWT 인증 구조를 어떻게 재정의했는지에 집중했습니다.
다음 글에서는:
  • 도메인 패키지(cctv, event, scenario)를 어떻게 나눴는지
  • 공통 UI 컴포넌트를 플랫폼 관점에서 설계한 기준
  • 모노레포에서 “분리해야 할 것”과 “절대 분리하면 안 되는 것”
이 주제들을 좀 더 구체적으로 정리해보려 합니다.
Share article

찬찬잉