JWT
- 사용자의 인증 정보를 서버 또는 클라이언트가 안전하게 전달하고 검증하기 위한 토큰 기반 인증 방식
장점
- 별도의 인증 저장소가 필요하지 않아 서버 부하를 낮춤
단점
- 탈취위험이 있음
- 토큰에 중요한 정보를 넣지 말고 많은 데이터를 넣지 않음
구성 요소

- 서명 및 토큰 검증에 사용하는 알고리즘
alg : 서명 암호화 알고리즘
typ : 토큰 유형
Payload
- 토큰에서 사용할 정보의 조각들인 클레임으로 구성, 등록된 클레임 외 추가 클레임을 넣을 수 있음
iss : 토큰 발급자(issuer)
sub : 토큰 제목(subject)
exp : 토큰 만료 시간(expiration)
aud : 토큰 대상자(audience)
iat : 토큰 발급 시간(issued at)
Signature
- 토큰을 인코딩하거나 유효성 검증에 필요, 토큰이 변조되지 않음을 확인
동작 원리

- 사용자 ID와 PW를 입력하여 로그인 요청
- 서버는 DB 조회하여 사용자 확인
- 확인이 되면 Token을 발급
- 클라이언트에게 전달
- 서비스 요청을 할 때 JWT도 같이 보냄
- 토큰을 확인하여 사용자 확인
- 서비스 요청이 정상적으로 이루어지고 응답을 클라이언트에게 보냄
토큰 종류
Access Token
- Http Request의 Authroization Headder에 넣은 토큰
- 일반적으로 JWT 형식을 많이 사용
- 토큰은 분실의 위험이 있기 떄문에 보통 30분 ~ 1시간의 유효기간을 가짐
- 어렵긴 하지만 서버에서 토큰을 취소하는 것이 불가능하진 않음
Refresh Token
- 새로운 Access Token을 얻을 수 있는 장기 토큰
- 보통은 특정 리소스를 위한 액세스 토큰을 얻음
- Refresh Token을 안전하게 사용할 수 있는 클라이언트만이 Refresh Token을 사용해야 함
코드 적용
설정
build.gradle
dependencies {
...
// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.13.0'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.13.0'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.13.0'
...
}
JWT 발급 및 검증 코드
키 설정
public class JwtUtil {
private String secretKey = "asdasdwqeqasdasdqwqdwdsadasdasdsadsadsadsaaaawwd";
private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
private Key key;
@PostConstruct
public void init() {
byte[] bytes = Base64.getDecoder().decode(secretKey);
key = Keys.hmacShaKeyFor(bytes);
}
...
}
secretKey : 비밀 키
signatureAlgorithm : 서명 알고리즘
key : JWT 서명/검증에 사용되는 암호화 Key
토큰 발급
public String generateToken(String username, ... 등등) {
long exp = 60 * 1000L;
Date date = new Date();
return "Bearer " + Jwts.builder()
.setSubject("여기는 제목")
.claim("auth", userRole)
.claim("name", username)
...
.setIssuedAt(date)
.setExpiration(new Date(date.getTime() + exp)
.signWith(key, signatureAlgorithm)
.compact();
}
claim : 사용할 정보를 집어 넣기
setIssuedAt : 발급 시간 설정
setExpiration : 만료 시간 설정
signWith : 비밀키와 알고리즘으로 서명
compact : JWT 토큰 생성
토큰 검증
public boolean validateToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return true;
} catch (Exception e) {
log.error("예외");
}
return false;
}
setSigningKey(key) : 비밀키 설정
parseClaimsJws : 토큰 파싱 및 검증