Intro
기존에 A사이트를 운영 중 색다른 기능의 B사이트 프로젝트 개발을 시작했다.
프로젝트의 요구 사항으로 A사이트와 로그인 연동이 필요했다.
이 말은, 아래와 같다.
- A에서 로그인된 상태로 B 이동 시 로그인 되어있을 것.
- B에서 로그인된 상태로 A 이동 시 로그인 되어있을 것.
Research
처음엔 A에서 session을 사용중이니까 이 session을 공유하는 방식으로 하려고 했다.
A와 B 둘 다 같은 redis
를 session store로 사용하면 같은 유저에 대해 session이 공유되지 않을까? 생각하였다.
하지만 테스트해 본 결과 생각과 달리 같은 client에 대해 각 서버는 각자의 session을 가졌다.
그래서 자료조사를 더 해보고 SAML
방식과 OAuth
방식으로 SSO(Single Sign On)
가 가능하다는 걸 알아냈다.
내 생각에 좀 더 트렌디 하다고 생각되는 OAuth 방식으로 시도했다.
SSO with OAuth
기본적인 OAuth의 Authorization Server를 구축하는 것은 그렇게 복잡하진 않지만
익숙하지 않은 사람이 뚝딱 만들 수 있을 만큼 단순하진 않다.
redirect
를 통해서 사이트를 왔다갔다 하기 때문에 query string에 callback url
을 넣는 방식을 쓴다.
Implementation
기본적으로 A에 login이 구현이 되어 있기 때문에 Authentication은 A에 일임하고,
A에 내부적으로 OAuth와 비슷한 형태의 API를 구성했다.
B에서 로그인 할 경우 A의 로그인 페이지로 callback url과 함께 redirect시키고,
로그인이 완료되면 A에서 B의 callback url로 redirect 시켜주는데 이 때 useId
를 query string으로 붙여준다.
그럼 사용자의 브라우저에서 B사이트로 userId
를 가지고 요청이 되었기 때문에 이제 B에선 userId
를 이용하여 유저가 누군지 알고 로그인 처리를 할 수 있다.
Implementation - 문제점
저렇게 구현하면 간단하다. 하지만 문제점이 무엇일까?
유저가 A에서 실제 로그인을 하지 않아도 B에서 로그인을 할 수 있다.
누군가 타인의 userId
값을 알고 있거나, 또는 userId
값이 숫자라서 아무 숫자나 B의 callback url에 대입하다가 맞아 떨어지면 바로 로그인 처리가 되어버린다.
Implementation - 2
다시 처음부터,
사전에 A와 B사이에 비밀 키(secretKey
)를 하나 공유한다.
secretKey
의 값은 그냥 문자열로 아무 값으로 해도 된다.
B에서 로그인 할 경우 A의 로그인 페이지로 callback url과 함께 redirect시키고,
로그인이 완료되면 A에서 B의 callback url로 authCode
를 query string으로 붙여서 이동시켜준다.
또한 나중에 authCode
를 통해 유저의 id를 반환하기 위해서 DB table을 하나 만들어두고 A의 로그인과 함께 auth_code
와 userId
를 DB에 저장한다. (일회용 데이터이기 때문에 redis같은 곳에 저장해도 상관 없다.)
그럼 이제 B에선 authCode
를 가지고 있고 secretKey
도 가지고 있다.
이 두가지 정보를 가지고 B에서 A로 직접 API를 요청한다.
그럼 A에선 secretKey
의 유효성을 검증하고 authCode
로 DB조회 하여 userId
를 찾을 수 있고, 그 값을 응답해준다.
그럼 이제 B에선 userId
를 알게되었고 로그인 처리를 하고 session
이나 JWT
로 로그인 처리를 하면 된다.
그림으로 정리하면 이렇다.

SSO with OAuth
P.S.
저 과정은 자유롭게 customizing이 가능할 것 같다.
- 보안을 좀 더 강화하기 위해
authCode
만 확인하는 것이 아니라 사전에 등록된 url에서 온 요청인지도 비교한다 - 더 간단한 방식으로
secretKey
로userId
를 암호화 및 검증해서 DB나 API 통신도 필요 없게 할 수 있다. - 실제 OAuth 서비스처럼
secretKey
도 API를 통해 등록되게 한다.
등등 여러 방법이 있을 것 같다.
일단 아직까지 저 방식에 문제가 있을 것 같지는 않아서 저렇게 적용하려고 한다.