이 글은 웹 개발 및 보안에 입문하는 초보자를 위해 JWT(Json Web Token)의 개념, 구조, 동작 원리, 실전 활용법을 계층적으로 설명합니다. 인증(Authentication)과 인가(Authorization)의 차이부터 JWT가 왜 등장했는지, 실제 서비스에서 어떻게 활용되는지까지 쉽게 안내합니다. 실전 코드 예시와 함께, JWT의 장단점, 보안 이슈, 그리고 실무 팁까지 한눈에 정리합니다.

목차

  1. JWT란 무엇인가?
  2. 인증과 인가의 차이
  3. JWT의 구조와 원리
  4. JWT 사용 흐름 (로그인~API 호출)
  5. JWT 실전 예제 (Kotlin 기반)
  6. JWT의 장점과 한계
  7. JWT 사용 시 주의할 점
  8. 결론 및 도움말
  9. 참고자료/레퍼런스
1. JWT란 무엇인가?

JWT(Json Web Token)는 웹 표준(RFC 7519)으로 정의된, 정보를 JSON 객체 형태로 안전하게 전송하기 위한 토큰 기반 인증 방식입니다. 주로 사용자 인증, 인가, 정보 교환 등에 활용됩니다. JWT는 “서명된 토큰”으로, 변조 여부를 쉽게 검증할 수 있어 분산 시스템이나 마이크로서비스 환경에서 널리 사용됩니다.

2. 인증(Authentication)과 인가(Authorization)의 차이
  • 인증: “너, 누구야?” 사용자의 신원을 확인하는 과정 (ex. 로그인)
  • 인가: “너, 이거 해도 돼?” 인증된 사용자가 특정 리소스/행동을 할 권한이 있는지 확인하는 과정 (ex. 관리자 기능 접근)

이 두 개념은 혼동하기 쉽지만, 실제 시스템 설계에서 반드시 구분되어야 합니다. JWT는 이 두 과정을 모두 지원할 수 있습니다.

3. JWT의 구조와 원리

JWT는 점(.)으로 구분된 3개의 파트로 구성됩니다:

  • Header(헤더): 토큰의 타입(JWT)과 서명 알고리즘 정보
  • Payload(페이로드): 실제 담고 싶은 정보(Claim)들. ex) userId, role, 만료시간 등
  • Signature(서명): 위 두 부분을 비밀키로 서명한 값
헤더.페이로드.서명

예시:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0Iiwicm9sZSI6InVzZXIiLCJleHAiOjE2ODg4ODg4ODh9.abc123...
  • 헤더: { “alg”: “HS256”, “typ”: “JWT” }
  • 페이로드: { “userId”: “1234”, “role”: “user”, “exp”: 1688888888 }
  • 서명: HMAC SHA256(헤더 + 페이로드, 비밀키)
4. JWT 사용 흐름 (로그인~API 호출)
  1. 사용자가 아이디/비밀번호로 로그인 요청
  2. 서버가 인증에 성공하면 JWT를 생성해 클라이언트(브라우저/앱)에 전달
  3. 클라이언트는 JWT를 로컬스토리지/쿠키 등에 저장
  4. 이후 모든 API 요청 시 JWT를 HTTP 헤더(Authorization: Bearer {토큰})에 실어 보냄
  5. 서버는 JWT의 유효성(서명, 만료 등)을 검사해 권한 부여
5. JWT 실전 예제 (Kotlin 기반)
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import java.util.Date

val secretKey = "mySecretKey"

// JWT 생성
fun createJwt(userId: String, role: String): String {
    return Jwts.builder()
        .setSubject("userInfo")
        .claim("userId", userId)
        .claim("role", role)
        .setExpiration(Date(System.currentTimeMillis() + 60 * 60 * 1000)) // 1시간
        .signWith(SignatureAlgorithm.HS256, secretKey)
        .compact()
}

// JWT 검증
fun validateJwt(token: String): Boolean {
    return try {
        val claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token)
        !claims.body.expiration.before(Date())
    } catch (e: Exception) {
        false
    }
}
6. JWT의 장점과 한계
  • 장점
    • 서버가 세션 상태를 기억할 필요 없음(Stateless)
    • 확장성, 분산 시스템에 적합
    • 다양한 정보(Claim) 포함 가능
  • 한계
    • 토큰 탈취 시 위험(재발급/폐기 어려움)
    • 토큰 크기가 커질 수 있음
    • 만료 전까지 권한 취소 어려움(블랙리스트 관리 필요)
7. JWT 사용 시 주의할 점
  • HTTPS(SSL/TLS)로만 전송(중간자 공격 방지)
  • 비밀키 노출 금지, 강력한 키 사용
  • 토큰 만료시간 꼭 설정
  • 민감 정보(비밀번호 등) 저장 금지
  • 토큰 저장 위치 주의(쿠키 XSS/CSRF, 로컬스토리지 XSS)
  • 로그아웃/권한변경 시 블랙리스트 등 별도 관리 필요
8. 결론 및 도움말

JWT는 현대 웹/모바일 서비스에서 인증과 인가를 간편하게 구현할 수 있는 강력한 도구입니다. 하지만, 만능은 아니며 보안 이슈와 한계를 반드시 이해하고 사용해야 합니다. 실전에서는 토큰 만료, 블랙리스트, HTTPS 적용 등 다양한 보안 대책을 꼭 병행하세요. 초보자라면 작은 실습 프로젝트부터 JWT를 적용해보며 경험을 쌓는 것을 추천합니다.

9. 참고자료/레퍼런스