안녕하세요! 이번 글에서는 **JWT(JSON Web Token)**에 대해 알아보고, 실제 애플리케이션에서 어떻게 활용되는지 정리해 보겠습니다. JWT는 사용자 인증과 권한 부여에 널리 사용되는 토큰 기반의 기술로, 서버와 클라이언트 간의 정보 교환을 안전하게 만듭니다. 🔐
1. JWT란 무엇인가?
JWT는 클레임(Claim) 기반의 정보를 JSON 객체로 안전하게 전송하는 것을 목적으로 하는 표준입니다. 토큰 자체에 사용자에 대한 정보를 담고 있어, 별도의 세션 저장소가 필요하지 않습니다.
JWT는 세 부분으로 구성됩니다. 각 부분은 .으로 구분됩니다.
- Header (헤더): 토큰의 타입(
JWT)과 서명에 사용될 해시 알고리즘(HS256,RS256등)을 포함합니다. - Payload (페이로드): 토큰에 담을 클레임(Claim), 즉 사용자 정보를 담습니다. 사용자의 ID, 이름, 권한 등 필요한 데이터를 여기에 넣을 수 있습니다.
- Signature (서명): 헤더와 페이로드를 Base64Url로 인코딩한 뒤, 서버의 **비밀 키(Secret Key)**로 서명하여 생성됩니다. 이 서명 덕분에 토큰이 위조되거나 변조되었는지 검증할 수 있습니다.
2. JWT 인증 과정
JWT를 활용한 인증은 보통 다음과 같은 절차로 이루어집니다.
- 로그인 요청: 사용자가 아이디와 비밀번호를 입력하여 서버에 로그인 요청을 보냅니다.
- JWT 생성: 서버는 사용자 정보를 확인하고, 인증이 성공하면 사용자의 고유 정보(예: ID)를 담은 JWT를 생성합니다.
- 토큰 발급: 생성된 JWT를 클라이언트에게 응답으로 보냅니다. 일반적으로 HTTP 응답 헤더의
Authorization필드에Bearer타입으로 담아 보냅니다. - 인증 요청: 클라이언트는 서버에 보호된 리소스(API)를 요청할 때, 발급받은 JWT를 요청 헤더에 포함하여 보냅니다.
- 토큰 검증: 서버는 요청 헤더의 JWT를 받아서 **서명(Signature)**을 검증합니다. 서명이 유효하다면 토큰의 페이로드를 디코딩하여 사용자 정보를 얻고, 요청을 처리합니다. 서명이 유효하지 않다면 인증 실패로 처리합니다.
3. JWT의 장점과 단점
장점:
- Stateless(무상태): 서버가 클라이언트의 상태를 저장할 필요가 없어 서버 확장에 유리합니다.
- 보안성: 서명(Signature)을 통해 데이터의 무결성을 보장합니다.
- 확장성: 여러 서비스 간에 토큰을 공유하여 싱글 사인온(SSO) 환경을 구축할 수 있습니다.
단점:
- 토큰 탈취: 토큰이 탈취될 경우, 만료되기 전까지 악용될 수 있습니다.
- 토큰 용량: 페이로드에 많은 정보를 담을수록 토큰의 크기가 커져 네트워크 부하가 증가할 수 있습니다.
- 정보 유출 위험: 페이로드는 인코딩만 되어 있어 누구나 볼 수 있습니다. 따라서 민감한 정보는 절대 페이로드에 담으면 안 됩니다.
4. 실제 프로젝트에 적용하기: Access Token과 Refresh Token
JWT의 단점인 ‘탈취’ 문제를 해결하기 위해, 보통 두 가지 종류의 토큰을 함께 사용합니다.
- Access Token (접근 토큰): 실제 리소스에 접근할 때 사용되는 토큰으로, 만료 기간을 짧게 설정합니다.
- Refresh Token (재발급 토큰): Access Token이 만료되었을 때, 새로운 Access Token을 발급받기 위해 사용되는 토큰입니다. Refresh Token은 만료 기간을 길게 설정하며, 서버의 데이터베이스에 안전하게 저장됩니다.
재발급 과정:
- Access Token이 만료되면, 클라이언트는 Refresh Token을 서버로 보냅니다.
- 서버는 Refresh Token의 유효성을 검사합니다.
- 유효하다면, 서버는 새로운 Access Token을 발급하여 클라이언트에게 보냅니다.
이 방식을 사용하면 Access Token이 탈취되더라도 만료 기간이 짧아 피해를 최소화할 수 있습니다.
5. Spring Boot에서 JWT 구현 예시
jjwt와 같은 라이브러리를 사용해 JWT를 쉽게 구현할 수 있습니다.
의존성 추가 (build.gradle)
dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
}
JWT 생성 및 검증 로직 (Service 또는 Util 클래스)

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
public class JwtTokenProvider {
private final SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private final long tokenValidityInMilliseconds = 3600000; // 1시간
// 토큰 생성
public String createToken(String username) {
Date now = new Date();
Date validity = new Date(now.getTime() + tokenValidityInMilliseconds);
return Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(key)
.compact();
}
// 토큰 유효성 검증
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (Exception e) {
// 토큰 검증 실패
return false;
}
}
}
위 코드는 JWT의 기본적인 생성 및 검증 로직을 보여줍니다. 실제로는 Spring Security와 함께 사용하여 인증 필터를 구현하는 것이 일반적입니다.
마치며
JWT는 현대적인 웹 애플리케이션에서 사용자 인증을 구현하는 데 있어 필수적인 기술입니다. Stateless한 특성 덕분에 확장성이 높고, 서명을 통해 데이터의 신뢰성을 확보할 수 있습니다. Access Token과 Refresh Token을 조합하여 보안을 강화하는 방법까지 이해하면 더욱 안전하고 효율적인 인증 시스템을 구축할 수 있을 것입니다. 🚀