프로그래밍/Infra

게이트웨이 서버에 인증・인가 적용기 ( 2편 )

코줍 2024. 6. 4. 20:06

들어가기 앞서...

게이트웨이 서버에 인증・인가 적용기 ( 1편 )

https://kojub.tistory.com/13

 

[ 기록의 정원 ] 게이트웨이 서버에 인증・인가 적용기 ( 1편 )

게이트웨이 서버라우팅 역할 게이트웨이 서버는 HTTP 요청을 다른 프로토콜로 변환해주어서 클라쪽에서 다른 프로토콜을 신경쓰지않고 통신할 수 있게끔하는 역할을한다. 약간 중간다리 같은

kojub.tistory.com

 

로그인 시 user서버에서 accessToken을 생성하여 response로 내려주었고,

token값을 header에 보내 다른 프로토콜로 API 요청을 할 때마다 회원 여부를 체크하여 통신을 할 수 있게끔 게이트웨이 서버를 구축했다.

 

 

 

RefreshToken

accessToken으로만 인증・인가 처리를 하다보니 Token이 만료됐을 때, 첫 메인화면에서 계속 401에러가 발생하면서 무한로딩 지옥에 빠져버렸다.

 

정석으론 RefreshToken도 같이 생성해서 response로 내려줘야 하는 게 맞지만, 굳이 필요하다고 생각하지 않았다.

왜냐면 예전에 회사에서 샵바이 API를 이용해 마켓을 개발할 때, Token 생성 API 요청 시 accessToken만 response에 내려줬기 때문이다. 이 때 인증・인가 로직이 꽤나 비합리적이였는데, 이거는 나중에 다시 글을 쓰겠다.

 

그러나, 

 

이러한 시점에서 refreshToken은 무한로딩을 발생시키지 않고

계속되는 에러로 무한 API 요청시도를 막기 위해 절대적으로 필요한 것이였다.

 

전략 : RefreshToken Rotation

RefreshToken을 도입하기 위해 oAuth 문서를 읽다가 RefreshToken Rotation 이라는 용어를 알게되었다. ( 참고 문서 🔗 )

 

이것은 Token이 탈취되는 시나리오를 대비하여 AccessToken이 만료될 때마다 상대적으로 유효기간이 긴 RefreshToken도 함께 재발급해주는 것을 의미한다. 매번 토큰이 새로 재발급되면서 탈취에 대한 위협이 줄어들 수 있다.

 

그리하여, AccessToken - 30분 / RefreshToken - 3일 

 

1. 로그인 시 response로 AccessToken과 RefreshToken을 내려준다.

 

2. AccessToken 만료될 경우 status가 401이고 error_message는 "Token has expired"인 에러를 발생시킨다.

 

3. header에 refresh-token 값을 넣어 아래와 같이 token을 재발행하는 API를 호출하여, 새로운 AccessToken과 RefreshToken값을 내려 받는다. 

curl --location --request POST '{도메인 이름}/user/token' \
--header 'refresh-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NGQ3YmI3Yi1lM2IyLTRkZTktYmEwOS0wNDdjMWZmOGEwNzMiLCJleHAiOjE3MjUwMzA5MDR9.CUZ-hlZbMRpHQBj3eELQw_wdf7mNuNSbflMqXldEXfc'

이 때, RefreshToken값도 만료된 경우엔 403에러를 발생시킨다.  ( 이 에러 status는 oAuth를 참고했다.

 

4. 새로 발급받은 AccessToken으로 기존에 요청하려고 했던 API를 다시 호출한다.

 

요렇게 해서 Token이 만료되더라도, 

사용자의 경험을 해치지 않는 ( 무한로딩 등 ... ) 인증・인가 로직을 구성했다 !

 

배운 점

RefreshToken의 역할을 좀 제대로 알았다고 해야할까?

구현 자체는 어려운 게 아니지만, 사용자의 경험을 해치지 않고 보안이슈까지 잡을 수 있는 방식이기 때문에 꼭 필요한 것이라는 생각이 들었다.

 

아 그리고 탈취 시나리오의 위협을 줄이는 다른 방법도 있다고 한다.

 

AccessToken 만료 시 RefreshToken으로 Token 재발급 요청을 하는 것이 아니라,

RefreshToken 을 heade값에 넣어 요청하려 했던 API를 재호출 하되 해당 RefreshToken으로 몇 번 요청을 했는지 서버쪽에서 인지하고 두 번이상 해당 RefreshToken으로 요청할 경우, 새로운 Token을 발행해주는....고런 방법...

 

이거는 Redis 같은 부가적인 DB가 따로 필요할 거 같은데, 한 번 나중에 시도해 봐야징