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 문을 넣어 확인해보았더니, 다음과 같이 회원정보를 잘 가져오는 것을 확인할 수 있었다!
'STUDY > Trouble Shooting' 카테고리의 다른 글
Timestamped ZonedDateTime 오류 (0) | 2024.05.22 |
---|---|
Redis Docker Container와 Spring Boot 연결이 안 되는 오류 (0) | 2024.05.22 |
Slack Webhook을 이용한 메시지 미리보기가 안되는 오류 (0) | 2024.05.22 |
GraphQL - mutation 실행 시 필드 값이 null로 들어오는 오류 (0) | 2024.04.18 |
Docker에서 Spring Boot 프로젝트 build 시 GraphQL 요청을 보내지 못하는 오류 (0) | 2024.04.18 |