Side Project Journey - 1. Between Root Domain And Sub Domain SSO based on Cookie
작년 2020년 11월 초부터 현재 재직 중인 회사 CPO 님과 2명이서 사이드 프로젝트를 하나 시작했다.
서비스 소개 영상이다.
제품의 아이디어 및 디자인 그리고 정체성 및 사용성에 대한 기획은 CPO 님이 그리고 나머지 기술 부문은 내가 맡아서 진행했다. 개발 스킬 향상을 위해서 혼자서 또는 개발자들끼리의 사이드 프로젝트를 진행한 경험은 많았지만, 사용자를 위한 제품을 만들기 위해서 진행한 사이드 프로젝트는 이번 경험이 처음이라고 할 수 있다.
Slack 과 Notion 을 이용하여 프로젝트에 필요한 커뮤니케이션을 진행했고, 퇴근 후 각자 주당 평균 10시간 정도 투자해서 100일 안에 완성을 목표로 시작했다. 100일을 목표로 잡은 이유는 100일이 넘어가면 늘어지고 지쳐서 서로가 힘들어지기 때문에 다소 타이트할 수도 있고 넉넉할 수 도 있는 시간으로 적절하게 잡았다. 또한 .new 라는 도메인을 사용했는데, 구글에서 만든 도메인으로 도메인 구입 후 100일 이내에 도메인을 적용한 서비스를 출시해야 되며, 구글에서 만든 정책을 준수하는 서비스를 만들어야한다.
이러한 과정속에서 제품을 만드는 과정에서 개발이외에 부분에서도 많은 것을 느끼고 성장한 부분도 있지만, 나는 엔지니어로서 기술적인 부분에서 고생을 하고 배운 것들에 대해서 정리를 해보려고 한다.
그 첫 번째 주제가 바로 SSO 이다.
간단하게 SSO 의 개념에 대해 먼저 짚어보겠다.
SSO 란 Single-Sign-On 의 약자이다. 우리나라말로 풀이하자면, 통합 인증 혹은 단일 인증 단일 계정 로그인 정도로 정리할 수 있다. 예시를 들자면, 우리 실생활에서 많이 사용하는 구글 서비스를 들 수 있다. 구글의 경우 한 번의 로그인을 통해서 Gmail, Youtube, Drive, Docs, Spreadsheet 등 여러 서비스를 사용할 수 있다.
구글의 여러 서비스의 경우, gmail 과 같이 mail.google.com 서브도메인으로 구성된 서비스도 있고, youtube 와 같이 youtube.com 과 같이 다른 도메인으로 구성된 서비스도 있다. 해당 경우에는 이번글에서 정리하려는 구현 방식과는 다르다. 유투브의 경우 일반적인 서비스 도메인은 youtube.com 인데, 채널을 운영 하시는 분이라면 동영상 관리 도메인은 studio.youtube.com 으로 서브도메인을 사용하고 있다.
이번 사이드 프로젝트를 하면서 SSO 를 구현한 방법은 Cookie 기반의 root domain 그리고 sub domain 서비스 들간의 SSO 를 구현한 것을 정리하려고 한다.
구체적으로 정리하자면, example.com 이라는 도메인을 소유하고 있다면
root domain 은 example.com 이 되고 최상위 도메인은 com 이된다.
그리고 서브 도메인은 depth 에 따라 여러가지 서브 도메인을 가질 수 있다.
1 depth 의 경우 shop.example.com, dashboard.example.com, admin.example.com
2 depth 의 경우 john.shop.example.com, doe.shop.example.com
최대 깊이는 제한이 없지만, hostname 의 최대 길이 255 로 제한된다.
자세한 내용은 rfc1034 section-3.1 을 참고하면 된다.
https://tools.ietf.org/html/rfc1034#section-3.1
다시 돌아와서, 이번 사이드 프로젝트의 요구사항은 example.com 과 dashboard.example.com 의 SSO 가 필요했다. 이 요구사항을 구현하는 과정에서 겪었던 삽질에 대해서 정리한다.
이번 사이드프로젝트를 진행하기 전에 구현해 본 인증 방식은 단일 도메인내에서만 가능한 방법이었다. 예를 들어, example.com 내에서만 사용하는 인증과 인가 방식 혹은 dashboard.example.com 내에서만 사용하는 인증과 인가 방식이다. 만약 MVC 패턴을 통해서 개발한다면, Cookie, Session 방식을 사용했었고, Front 와 Back 이 분리된다면, local storage 를 통한 Token 인증 방식을 사용했었다. 따라서 해당 방식으로 접근했을 때, example.com 에서 인증을 받았을 때, dashboard.com 에서는 인증을 다시 받아야하는 상황이 발생했다.
localStorage 의 경우, 서브도메인까지 완전히 일치해야지 localStorage 공유가 가능하며, 따라서 루트 도메인과 서브도메인 간의 공유가 불가능하다.
sessionStorage 의 경우, 더 큰 제약이 있다. 왜냐하면, sessionStorage 는 브라우저의 탭마다 고유하게 동작하기 때문에, 탭/창을 끄게 되면 해당 sessionStorage 는 초기화 된다.
localStorage 와 iframe 과 postMessage 를 통해서 다른 도메인간의 메세지를 주고 받을 수 있지만, 해당 케이스는 인증과 관련된 케이스를 다루기에 적합하지 않고, 개발 및 운영 관점에서도 좋은 선택이 아니라서 제외했다.
그래서 최종으로 선택한 방법이 루트 도메인에서 인증 서버를 통해서 인증을 받은 후 JWT(Json Web Token) 를 받는다. 그리고 JWT 를 루트 도메인 cookie 를 이용하여 cookie 를 생성하고 서브도메인으로 redirect 시키는 방법이다. 서브 도메인에서는 루트 도메인에 대한 쿠키의 존재여부와 해당 쿠키 값인 JWT 을 사용하여 자원 서버와 통신하는 구성을 취했다.
먼저 루트 도메인에서의 JWT 를 Cookie 값으로 지정하고 생성하는 코드 부분의 발췌이다.
그리고 아래에는 인증을 받고 서브 도메인에서 처음 인증을 처리하는 부분이다. front 스택은 모두 angular11 로 만들었다. 따라서 component life cycle hook mehotd 인 ngOnInit() 을 이용했다.
인증이 되었으면, u/dashboard 로 라우팅하고, 되어 있지 않을 경우 다시 루트 도메인으로 redirect 시킨다.
마찬가지로 로그아웃도 루트 도메인의 cookie 를 만료시키는 형태로 구현하였다.
서브도메인에서 로그아웃을 진행하기 위해서 서브도메인의 localStorage 를 비워주고, 루트도메인에 지정된 Single Sign out 으로 redirect 시킨다.
localStorage 을 사용하지 않고, 바로 Cookie 에서 값을 꺼내 JWT 로 api 통신을 해도 가능하지만, 개발상의 편의로 cookie 를 파싱하는 것보다 localStorage 에서 바로 getItem 을 통해서 JWT 을 사용했다.
이번 글의 내용은 여기서 마무리하고, 사이드 프로젝트를 진행하면서 느낀것들과 기술적으로 고생했던 부분들을 앞으로 더 정리할 예정이다.
댓글
댓글 쓰기