일단 시작.

만료된 토큰에서 토큰에 저장된 정보를 가져올 수 없는 오류 본문

STUDY/Trouble Shooting

만료된 토큰에서 토큰에 저장된 정보를 가져올 수 없는 오류

꾸양! 2024. 5. 22. 16:20

1. Issue Description


만료된 Access Token에서 추출한 회원 정보로 저장된 Refresh Token을 조회하여 같은지 확인하려는데 다음과 같은 예외가 발생했다.

io.jsonwebtoken.ExpiredJwtException: JWT expired at 2024-05-20T10:23:30Z. Current time: 2024-05-20T12:01:17Z, a difference of 5867735 milliseconds.  Allowed clock skew: 0 milliseconds.
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:427) ~[jjwt-impl-0.11.5.jar:0.11.5]
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:529) ~[jjwt-impl-0.11.5.jar:0.11.5]
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:589) ~[jjwt-impl-0.11.5.jar:0.11.5]
	at io.jsonwebtoken.impl.ImmutableJwtParser.parseClaimsJws(ImmutableJwtParser.java:173) ~[jjwt-impl-0.11.5.jar:0.11.5]
	at com.twoPotatoes.bobJoying.common.security.JwtUtil.getUserInfoFromToken(JwtUtil.java:107) ~[main/:na]
	at com.twoPotatoes.bobJoying.common.security.JwtUtil.getUserEmailFromExpiredToken(JwtUtil.java:116) ~[main/:na]
	at com.twoPotatoes.bobJoying.member.service.AuthServiceImpl.reissueToken(AuthServiceImpl.java:55) ~[main/:na]

 

2. 원인 추론


메서드를 쭉 타고 올라가다 보니 내가 사용한 JWT 라이브러리에서는 Token에서 subject를 얻을 때 기한이 만료된 토큰의 경우 무조건 ExpiredJwtException이 발생하게끔 되어 있었다.

public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
...
    if (claims != null) {
        Date now = this.clock.now();
        long nowTime = now.getTime();
        Date exp = claims.getExpiration();
        String nbfVal;
        if (exp != null) {
            long maxTime = nowTime - this.allowedClockSkewMillis;
            Date max = allowSkew ? new Date(maxTime) : now;
                if (max.after(exp)) {
                    String expVal = DateFormats.formatIso8601(exp, false);
                    nbfVal = DateFormats.formatIso8601(now, false);
                    long differenceMillis = maxTime - exp.getTime();
                    String msg = "JWT expired at " + expVal + ". Current time: " + nbfVal + ", a difference of " + differenceMillis + " milliseconds.  Allowed clock skew: " + this.allowedClockSkewMillis + " milliseconds.";
                    throw new ExpiredJwtException((Header)header, claims, msg);
                }
        }
...
  • 라이브러리를 바꿔야 하나?
    • Security 설정, JwtUtil, 등등 바꾸어야 할 것이 너무 많아서 일단은 pass
    • 현재 라이브러리에서 할 수 있는 것을 찾아보자.
  • 만료된 Access Token으로 Google 검색
    • Refresh Token 구현에 관한 내용만 나온다.
  • 라이브러리 그 자체로 검색하기 -> io.jsonwebtoken extract inform from expired token

딱 내가 원하는 글이 있었다! 해당 글슨이도 나와 같은 라이브러리를 쓰면서 같은 문제가 생겨 Stack Overflow에 글을 올렸는데, 답변은 다음과 같았다.

  • 첫 번째 답변 : try-catch를 이용해 예외를 잡고 그 예외의 claim을 이용해 정보를 추출하는 방법

  • 두 번째 답변 : JWT 자체가 Base64로 인코딩되어 있으므로 Base64 디코딩을 이용하여 추출하는 방법

1번 답이 좀 더 직관적으로 보이고 간단해 보여서 1번으로 해결해 보기로 했다.

 

3. 해결


기존 코드를 다음과 같이 바꾸어보았다.

Claims claims;
try {
    claims = getUserInfoFromToken(subToken);
} catch (ExpiredJwtException e) {
    return e.getClaims().getSubject();
}
return claims.getSubject();

 

 

4. 결과


위 코드에서 catch 단에 print 문을 넣어 확인해보았더니, 다음과 같이 회원정보를 잘 가져오는 것을 확인할 수 있었다!