Laravel JWT Refresh Token 작업...

Updated on

한동안 Docker 작업하느라.. 개발을 제대로 못했다.. (그래도 이제는 도커에 대해서 많은걸 이해했다.. 전반적으로 사용은 가능할 정도…)

그래서, 계속해서 작업 들어가는건 Laravel JWT Refresh Token인데..
JWT에 대한 개념도 모호하기도 하고, 세션(쿠키)랑 뭐가 다른가 싶기도 하고… 참으로 난감하고 어려운 문제들이 많다… (나만의 문제..)

어쨌든, 내가 구상하는 것은, 토큰 유지시간이 주어지고, 리프레쉬 시간을 주어진다. (tymon/jwt)
유지시간이 만료되고 나서, 종료된 토큰으로 호출하면, Laravel middleware 에서는 해당 토큰의 리프레쉬 시간 안이라면, 새로운 토큰을 발급하고, 헤더에 새로운 토큰 값을 포함해서 리스폰한다. (이때, 당연히 해당 결과값은 출력해준다)

그렇게, Nuxt.js(클라)에서 받은 리스폰 헤더에 토큰이 존재한다면, 새로운 토큰을 발급 받은것으로 판단해서, 새로운 토큰으로 교체하고, 새롭게 Nuxt.js Auth Module 에서 user 를 호출해서, payload 값을 새롭게 받아와서 로컬 스토리지에 저장한다.

자, 여기까지가 내가 구상한건데..
tymon 에서 리프레쉬 시간이 지나면, 무조건 해당 토큰은 죽어버리게 되어 있다.
여기까지 좋다.. 근데… 지금 현재 발생하는 문제점은 두가지다.

  • 토큰 만료가 되고, 리프레쉬 시간 안에 요청해서, 새로운 토큰을 발급 받은 새로운 토큰의 만료시간이 지나면, 더 이상 리프레쉬가 되지 않는다. (리프레쉬 시간 값 안에서는 지속적으로 토큰을 재발급 받을 수가 있어야 하는데, 이것이 되지 않는다 !! 딱 한번만 되.. 왜지? ㅠㅠ)

JWT_TTL=1 JWT_REFRESH_TTL=2

아니.. 이렇게 값을 주고 했었다… 알고보니.. REFRESH_TTL 같은 경우는 계속해서 늘어나는 것이 아니라, 마지막 한계 값인 것이다. iat 기준으로 TTL시간이 지나버리면, 더 이상 해당 토큰은 무엇을 해도 사용할 수 없게 된다. (마지막 생명시간)

즉, 리프레쉬 토큰 값이 지나기 전까지는 리프레쉬를 무제한으로 할 수 있다가 옳은 정보.

  • 리프레쉬하게 되면, exp (만료시간)과 nbf (활성시간)이 바뀌게 되는데.. (당연한 것) 하지만, getJWTCustomClaims() 에 해당하는 Claims는 새로운 데이터로 바뀌지 않는다… (내가 원하는 것은, 리프레쉬와 동시에 해당 토큰의 Claims 값들을 새롭게 받아오고 싶다 !! 그렇지 않으면, 닉네임이 변경 됬을때, 또는 중간에 유저의 상태 값을 밴 처리 했을때 기타 등등 반영이 안되지 않는가… 적어도 토큰 재발급 할때에는 claims 값들도 리프레쉬 되서 들어가고 싶다… 그게 아니라면, 토큰에는 잘 변하지 않는 것들로만 구성해야 되게 될 것이다…)

대충 이 정도 인데… 일단 1번부터 해결하고, 나머지 2번을 해결해야 될 듯 싶다..
2번 같은 경우는 정 안되면, 토큰에는 user 값만 저장하고나서, Nuxt.js Auth에서 User 불러올때, 유저 정보를 뿌려 주고, 해당 정보를 로컬 스토리지에 저장시키는 방법 밖에는 없다..
(즉, 토큰 Payload 안에는 유저 이메일, 이메일 인증여부, 값 상태, Role 기타 등등 값을 넣을 수 없다는 이야기이다….)

빨리, 하나씩 작업 해보도록 하겠다…
워낙 tymon/jwt 자료가 없기에.. 해당 github issue 에서 찾아보면서 하는 수 밖에 없는것 같아서 너무 불편하다….

2번째 문제의 경우 해결 방안은
https://github.com/tymondesigns/jwt-auth/pull/1619
https://github.com/Blog-Ecommerce/jwt-auth/
https://github.com/Blog-Ecommerce/jwt-auth/commit/26a6547274f05467c92192677f3f25678a383bfd

이렇게 2가지 방법이 있었다.
JWT 리프레쉬할때, 유저 데이터를 넣어서 새로 고치는 방법인데..
이 방법은 JWT.php 소스 자체를 수정하는 방법인데.. 나중에 버전 업하거나, 새로 패키지 설치 등에서 매번 수정 해줘야하는 번거로움이 있어서 별로 하고싶지 않았다..

그렇다고, getJWTCustomClaims() 에 Claims을 없애고, 토큰에는 유저 값만 부여하고, User 데이터 받아 오는 곳에서 받아오는 방법 또한 별로 하고싶지 않았다…
(이유는 모르겠다, 사실 이 방법이 가장 편한 방법이였지 않을까 싶은데…)

그래서 해결한 방법은..

토큰이 만료됬다면, 리프레쉬 해주고, 리프레쉬한 토큰으로 Auth에 세팅하고, Payload로 데이터를 받아온 다음에, 새로운 토큰을 생성한다. 이때 iat 값은 페이로드한 값으로 주고, tokenById로 sub값을 줌으로써, 유저 아이디 값도 동일시 하게해서 새롭게 토큰을 생성한다.

$this->checkForToken($request);
$token = $this->auth->parseToken()->refresh();

// 토큰 새로고침할때, payload 정보도 새로 고쳐야 한다 !!
auth()->setToken($token);
// 새로운 토큰 재 발행 (기존 EXP 유지한 채로)
$payload = auth()->payload();
auth()->invalidate();
$token = auth()->claims(['iat' => $payload['iat']])->tokenById($payload['sub']);
auth()->setToken($token);

이렇게 작성하면, 리프레쉬된 토큰에서 페이로드로 기존 토큰의 iat와 sub만 가지고 새로운 토큰을 생성하게 된다.
그리고 리프레쉬 된 토큰은 바로 invalidate 처리하여 없애준다.
그렇게 iat값이 고정된 새로운 토큰은 auth에 셋팅 시켜줌으로써, 정상적인 JWT토큰으로 사용이 가능하게 된다.

비록, Refresh Token을 발행했다가, 다시 토큰을 없애기 때문에, 리프레쉬 할때마다 2번 중복 작업을 하게 되긴 하지만… 차라리 JWT.php 를 수정하는 것보다, 이렇게 처리하는게 더 좋을 것 같아서 이렇게 하게 되었다.. (굳이 리프레쉬한걸 Auth에 등록 안하고 바로 페이로드해서 해도 될 것같긴 한데… 더 디테일하게 작업 하기에는 시간이 더 소요되기 때문에 나중에 문제되면 작업하는거로… JWT 어렵다..)

https://github.com/tymondesigns/jwt-auth/issues/1792