JWT(JSON Web Token) 개념과 실습

Hanu·2026년 4월 17일

BACK-END

목록 보기
1/1

1. JWT란 무엇인가?

JWT(JSON Web Token)는
사용자 인증 정보를 담아 서버와 클라이언트 간에 안전하게 전달하기 위한 토큰 기반 인증 방식이다.

핵심 목적:

  • 인증(Authentication)
  • 정보 전달(Authorization)
  • Stateless 서버 구현

2. JWT 구조

JWT는 3개의 문자열로 구성된다.

Header.Payload.Signature

예시:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VySWQiOiJoYW51bCJ9
.
abc123signature

3. 각 구성 요소

1) Header

토큰의 타입과 서명 알고리즘을 명시

{
  "alg": "HS256",
  "typ": "JWT"
}

2) Payload

실제 데이터

{
  "userId": "hanul"
}

⚠️ 민감한 정보는 절대 넣으면 안됨 (평문 노출됨)


3) Signature

위조 방지를 위한 서명

HMACSHA256(
  base64Url(Header) + "." + base64Url(Payload),
  secretKey
)

4. Base64 vs Base64Url

Base64 문제

  • +, /, = → URL, HTTP에서 문제 발생

Base64Url

  • +-
  • /_
  • = 제거

👉 JWT는 HTTP 환경에서 안전하게 사용하기 위해 Base64Url 사용


5. JWT의 핵심 개념

JWT는 암호화가 아니다

  • Payload는 누구나 읽을 수 있음

대신 "서명(Signature)"으로 보호

  • 위조 방지
  • 서버만 secret을 알고 있음

6. JWT 인증 흐름

1. 로그인 요청
2. 서버 → JWT 발급
3. 클라이언트 → 토큰 저장
4. 요청 시 JWT 포함
5. 서버 → 토큰 검증

7. 왜 JWT를 쓰는가?

장점

  • 서버 상태 저장 없음 (Stateless)
  • 확장성 좋음 (MSA 환경)
  • 빠른 인증 처리

단점

  • 토큰 탈취 시 위험
  • 로그아웃 어려움
  • 토큰 크기 큼

8. 순수 Java JWT 실습


📁 프로젝트 구조

Base64UrlUtil.java
JwtSignatureUtil.java
JwtUtil.java
JwtValidator.java
Main.java

Base64UrlUtil.java

import java.util.Base64;

/* Base64Url 인코딩 */
public class Base64UrlUtil {
	public static String encode(byte[] data) {
		return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
	}

	public static String encode(String data) {
		return Base64.getUrlEncoder().withoutPadding().encodeToString(data.getBytes());
	}

	public static String decode(String data) {
		return new String(Base64.getUrlDecoder().decode(data));
	}
}
  • JWT는 URL/HTTP 헤더에서 안전하게 사용하기 위해 Base64Url을 사용한다.
  • 일반 Base64에는 +, /, = 가 포함되어 서버나 브라우저가 해석하면서 문제가 생길 수 있다.
  • JWT는 쿠키, URL, 헤더에 들어가야 하므로 HTTP 전반에서 안전하게 전달될 수 있어야 한다.
  • 따라서 Base64Url은 -, _, 패딩 제거로 문자열을 치환한다.

JwtSignatureUtil.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class JwtSignatureUtil {

    public static String createSignature(String data, String secret) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        mac.init(key);

        byte[] rawHmac = mac.doFinal(data.getBytes());

        return Base64UrlUtil.encode(rawHmac);
    }
}
  • 서버만 아는 SECRET으로 서명한다.
  • 이를 통해 서버는 세션 저장 없이도 인증을 할 수 있기에 상태를 관리하지 않아도 된다.

JwtUtil.java (토큰 생성)

public class JwtUtil {

    private static final String SECRET = "my-secret-key";

    public static String createToken(String userId) throws Exception {

        String header = Base64UrlUtil.encode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}");
        String payload = Base64UrlUtil.encode("{\"userId\":\"" + userId + "\"}");

        String data = header + "." + payload;

        String signature = JwtSignatureUtil.createSignature(data, SECRET);

        return data + "." + signature;
    }
}
  • header : 어떤 알고리즘을 썼는지
  • payload : 실제 데이터(userId 등)
  • signature : 위 두 개를 기반으로 만든 서명

JwtValidator.java (토큰 검증)

public class JwtValidator {

    private static final String SECRET = "my-secret-key";

    public static boolean validate(String token) throws Exception {

        String[] parts = token.split("\\.");

        if (parts.length != 3) return false;

        String header = parts[0];
        String payload = parts[1];
        String signature = parts[2];

        String data = header + "." + payload;

        String newSignature = JwtSignatureUtil.createSignature(data, SECRET);

        return signature.equals(newSignature); // jwt 서명 생성 결과 비교 
    }
}

Main.java (테스트)

public class Main {

    public static void main(String[] args) throws Exception {

        String token = JwtUtil.createToken("Hanul");

        System.out.println("JWT: " + token);

        boolean valid = JwtValidator.validate(token);

        System.out.println("검증 결과: " + valid);

        // Payload 디코딩
        String payload = Base64UrlUtil.decode(token.split("\\.")[1]);
        System.out.println("Payload: " + payload);
    }
}
  • 출력 결과


요약

  • JWT = Header + Payload + Signature
  • Base64Url로 문자열 인코딩
  • 암호화 ❌ / 서명 기반 위조 방지 ⭕
  • 서버 상태 없이 인증 가능


이미지 출처: https://blog.algomaster.io/p/json-web-tokens


profile
필연적인 프로그래밍

0개의 댓글