[Web] oAuth 2.0 & JWT

Dev·2021년 9월 28일
1
post-custom-banner

1. oAuth 2.0

어떤 서비스의 회원 정보를 다른 서비스에게 접근 권한을 부여하는 Open Authorization 입니다. 여기서 어떤 서비스란 구글, 페이스북, 네이버 등 많은 유저를 보유한 서비스를 말합니다.

[1] oAuth 2.0이란

예를 들어 어느 스타트업에서 알파 서비스를 개발 하려고합니다. 당연히 id, pw, 이름, 번호 등의 유저의 개인 정보를 받아옵니다. 이는 다음의 불편함이 있습니다.

  • 유저는 다른 서비스에서 회원가입을 했는데 또 하기는 귀찮습니다. UX상 회원가입은 간편할수록 좋습니다.
  • 알파 서비스 개발자는 반드시 회원 정보를 관리해야합니다.

따라서 oAuth 2.0을 사용하면 아래의 편의성이 존재합니다.

  • 유저는 3rd party service의 회원정보를 활용해 회원가입합니다. 회원가입 UX의 편리함이 생깁니다.
  • 유저의 정보를 알파 서비스 DB에 저장하지 않는다면 회원 정보 관리 책임을 rd party service에게 위임할 수 있습니다.
  • 3rd party service api를 쉽게 사용할 수 있습니다.
  • 단 유저는 3rd party service에 회원가입이 되있을 경우에만 이용 가능합니다.

즉, 하나의 애플리케이션만 가입한다면 다양한 애플리케이션에서 각각 사용자가 권한을 부여 받을 필요 없이 A 애플리케이션으로 부터 부여 받은 권한을 다양한 애플리케이션에서 활용할 수 있습니다.

[2] oAuth 2.0 동작 원리

구분설명
ClientoAuth 2.0을 사용해 3rd party api login 기능을 구현할 서비스입니다. 상황에 따라 서비스 클라이언트 혹은 서비스 서버가 될 수있습니다.
Resource Owner3rd party application에 가입한 유저로, client service를 사용할 유저입니다.
Resource Server3rd party application (google, facebook, naver)으로, 회원정보를 저장하고 있는 서버입니다. client는 toekn을 이 서버로 넘겨 개인정보를 주고 받습니다.
Authorization Server3rd party application (google, facebook, naver)으로 권한을 부여해주는 서버입니다. 이 서버로부터 클라이언트는 authorization code 및 token을 지정된 redirect uri로 넘겨 받습니다.

  • 0 ~ 2 : 사전 등록 과정 : 서비스가 resource server에게 당신의 서비스를 사용할것이라고 등록하는 과정이 필요합니다. 이때 각각의 client를 식별하는 client_id, client_secret과 이후 authorization code 및 access_token을 발급받을 redirect_url를 지정합니다.
  • 3 ~ 7 : 이후 사용자가 resource server의 기능을(로그인, 유저정보 불러오기 등) 사용하고 싶다면 인증 절차를 거쳐야합니다. 로그인, 우리 서비스에서 해당 데이터를 가져와도 되는지 등의 절차를 거칩니다. 성공 완료시, client_id에 맞는 redirect_url에 authorization code를 발급해줍니다. 여기서 바로 access_token을 발급하지 않은 이유는 정확하진 않지만 보안..?을 위해서라고 추상적으로 알고있습니다.
  • 8 ~ 9 : 이제 클라이언트는 authorization code, id, pw, redirect_url의 정보를 가지고 resource server에게 access_token 정보를 요청 후 redirect_url로 전달 받습니다.

여기서 client라고 말하는 것은 android/ios, web, server 모두가 될 수 있습니다. 따라서 어떤 파트가 이 부분을 개발할지에 대해서는 팀원간 상의가 필요합니다.

[3] oAuth 2.0 Examaple

어디까지 프론트엔드가 관여할지 어디까지 백엔드가 관여할지는 팀원간의 상의가 필요합니다.

Backend가 주 개발
1. 프론트엔드에서 로그인 버튼을 클릭합니다. (alphaService.com/oauth)
2. 프론트엔드의 요청을 백엔드가 받아들이고 google 로그인 페이지로 redirect합니다.
3. 사용자가 구글 로그인합니다.
4. 초기에 지정한 redirect uri로 구글이 authorization code를 반환합니다.
5. 백엔드에서 authorization code를 통해 구글 서버로부터 token을 받아옵니다. (spring security oauth 2.0은 내부적으로 수행합니다.)
6. 백엔드는 자체 jwt 토큰을 만들고 프론트엔드쪽으로 redirect합니다.

프론트엔드가 code 관여
1. 프론트엔드에서 직접 구글 로그인 버튼을 클릭합니다. (accounts.google --- /client_id=...)
2. 사용자가 프론트엔드에서 구글 로그인을 완료합니다.
3. 구글 서버는 authorization code를 프론트엔드로 redirect합니다.
4. 프론트엔드는 백엔드에게 authorization code를 redirect합니다.
5. 백엔드가 구글 서버로부터 token을 받아옵니다.
6. 백엔드는 자체 jwt를 만들고 프론트엔드에게 토큰을 전송합니다.

2. JSon Web Token

[1] JWT란

HTTP는 Stateless, Connectionless 특징을 가집니다. 서버는 클라이언트의 모든 정보를 기억하지 않으며, 클라이어늩와 연결과 끊음을 반복합니다. 따라서 패킷을 주고 받을 때 이 패킷이 어떤 유저에 정보인지를 알아야합니다. 이를 위해 서버에서는 세션 및 DB, 클라이언트에서는 쿠키에 토큰 값을 저장하고 패킷 헤더에 토큰을 담아 통신합니다.

토큰은 어떤 유저인지를 지칭하는데 그러면 ID, 전화번호와 같은 유니크한 값을 넣어 전달하면 될까요? 물론 방법일 수는 있지만 보안상 유니크한 값을 시크릿 키 기준으로 암호화 하고 이후에 복호화하는 매커니즘을 권장합니다.

[2] Access Token

유저를 식별하는 유니트 값을 암호화한 토큰으로, 패킷 Authorization 헤더에 담아 전송합니다. 만약 하나의 Access Token만 사용하면 아래의 문제가 발생합니다.

  • 유효기간이 긴 경우, 한 번 탈취당한 토큰은 해커가 긴 시간동안 악용할 수 있어 위험합니다.
  • 유효기간이 짧은 경우, 토큰이 만료될 때마다 사용자는 다시 로그인을 해야 하기 때문에 UX에 치명적입니다.

이러한 문제를 해결하기 위해, 유효기간이 짧은 Access Token과 유효기간이 긴 Refresh Token 두 가지를 함께 사용합니다.

[3] Refresh Token

  • Refresh Token은 Access Token 재발행을 위한 인증 토큰입니다.
  • 보통 Refresh Token은 DB, Access Token은 세션 혹은 메모리에 저장합니다. 왜냐하면 Access Token은 자주 접근하며, 유효 기간이 짧아 자주 갱신되기 때문입니다.
  • 상황에 따라 두 토큰 모두 DB에 저장하기도합니다.
  • 보통 유효기간은 Access Token 1시간, Refresh Token 2주 정도로 잡는다고 알려져 있습니다.

[4] 토큰 발급 플로우 예제

  1. 최초 로그인 시 서버는 Refresh Token과 Access Token을 모두 클라이언트에 발급해줍니다.
  2. 이때 서버는 Access Token을 세션, Refresh Token은 DB에 저장합니다. 반면 클라이언트는 로컬 안전한 곳에 Refresh Token을 저장하고 통신에는 Access Token을 사용합니다.
  3. Access Token으로 통신하다 중간에 유효기간이 만료되었다는 응답을 서버로부터 받은 클라이언트는 Refresh Token을 꺼내어 재전송하고, 서버는 DB에 있는 Refresh Token과 받은 Refresh Token을 대조하여 Access Token 재발행 여부를 결정합니다. Refresh Token도 만료된 경우에는 재로그인을 해야 한다.

즉, Access Token으로 평소에 통신하다 유효 기간이 만료되면 Refresh Token을 주어 다시 Access Token을 재발급 받습니다. 따라서 적절한 유효기간을 부여하여 성능을 최적화하고 보안을 유지하는 것이 중요합니다.

profile
성장하는 개발자가 되고싶어요
post-custom-banner

0개의 댓글