Spring Boot

JWT 토큰 만료 시간을 설정하고 관리하는 방법

Pro.Dev 2025. 1. 8. 15:01
반응형

JWT 토큰 만료 시간을 설정하고 관리하는 방법

JWT(JSON Web Token)는 클라이언트와 서버 간에 안전하게 정보를 전송하기 위해 널리 사용되는 토큰 기반 인증 방식입니다. JWT에는 만료 시간(expiration)을 설정하여 보안성을 강화할 수 있습니다. 이 글에서는 JWT 토큰의 만료 시간을 설정하고 이를 효율적으로 관리하는 방법을 단계별로 설명합니다.


1. JWT 만료 시간의 필요성

JWT는 기본적으로 클라이언트 측에서 상태를 유지하지 않는(stateless) 인증 방식입니다. 토큰의 유효 기간을 설정하지 않으면 만료되지 않고, 보안 취약점이 생길 수 있습니다.

만료 시간 설정의 장점:

  • 보안 강화: 토큰이 도난당했을 경우 제한된 시간 내에만 사용할 수 있습니다.
  • 리소스 관리: 오래된 토큰이 무효화되어 서버에서 더 이상 사용되지 않도록 합니다.

2. JWT 토큰 생성 시 만료 시간 설정

JWT의 exp 클레임을 사용하여 토큰의 만료 시간을 설정할 수 있습니다. 이 값은 UNIX 타임스탬프로 지정됩니다.

예제 코드:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtUtil {

    private final String SECRET_KEY = "mysecretkey";
    private final long ACCESS_TOKEN_EXPIRATION = 1000 * 60 * 15; // 15분
    private final long REFRESH_TOKEN_EXPIRATION = 1000 * 60 * 60 * 24 * 7; // 7일

    public String generateAccessToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public String generateRefreshToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + REFRESH_TOKEN_EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
}

설명:

  • ACCESS_TOKEN_EXPIRATION: 액세스 토큰의 만료 시간을 15분으로 설정
  • REFRESH_TOKEN_EXPIRATION: 리프레시 토큰의 만료 시간을 7일로 설정

3. JWT 토큰 만료 확인

토큰이 만료되었는지 확인하려면 exp 클레임을 사용하여 현재 시간과 비교하면 됩니다.

예제 코드:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtValidator {

    private final String SECRET_KEY = "mysecretkey";

    public boolean isTokenExpired(String token) {
        Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
        return claims.getExpiration().before(new Date());
    }
}

설명:

  • claims.getExpiration(): 토큰의 만료 시간을 가져옵니다.
  • before(new Date()): 현재 시간보다 만료 시간이 이전인지 확인합니다.

4. 만료된 토큰 처리

  1. 새로운 액세스 토큰 발급:

    • 리프레시 토큰을 사용해 새로운 액세스 토큰을 발급합니다.
    • 클라이언트가 서버에 다시 인증하지 않아도 됩니다.
  2. 토큰 무효화:

    • 만료된 토큰은 더 이상 사용되지 않도록 클라이언트와 서버가 협의해야 합니다.

5. 유효 기간 관리 전략

  1. 짧은 액세스 토큰, 긴 리프레시 토큰:

    • 액세스 토큰은 15분~1시간으로 짧게 설정
    • 리프레시 토큰은 1주일~1개월로 길게 설정
  2. 환경에 따른 설정:

    • 개발 환경: 액세스 토큰과 리프레시 토큰의 만료 시간을 길게 설정
    • 프로덕션 환경: 보안을 위해 짧은 만료 시간 사용
  3. 토큰 재사용 방지:

    • 리프레시 토큰 사용 시마다 새로운 리프레시 토큰을 발급
    • 데이터베이스에 저장된 기존 리프레시 토큰 무효화

예제:

public String refreshTokens(String refreshToken) {
    if (isTokenExpired(refreshToken)) {
        throw new IllegalStateException("리프레시 토큰이 만료되었습니다.");
    }

    String username = extractUsername(refreshToken);
    return generateAccessToken(username);
}

6. 로그아웃 시 만료 처리

로그아웃 시 서버에서 리프레시 토큰을 무효화해야 합니다.

  1. 데이터베이스에서 삭제:

    • 사용자의 리프레시 토큰을 데이터베이스에서 제거
  2. 블랙리스트 사용:

    • 만료된 리프레시 토큰을 블랙리스트에 추가하고, 블랙리스트를 확인하여 사용 방지

예제:

public void logout(String username) {
    refreshTokenRepository.deleteByUsername(username);
}

7. 테스트 및 실행

  1. 토큰 생성 테스트:

    • 로그인 시 액세스 토큰과 리프레시 토큰을 생성하고 반환
  2. 만료된 토큰 처리 테스트:

    • 만료된 액세스 토큰으로 요청 시 401 Unauthorized 응답 반환
    • 리프레시 토큰을 사용해 새로운 액세스 토큰 발급

반응형