1. JWT의 정의와 특징

JWT는 당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 표준이다. 웹에서 인증과 권한 부여를 구현할 때 가장 널리 사용되는 수단 중 하나이다. 토큰 자체가 사용자의 권한 정보나 서비스 상태를 포함하고 있어, 이를 수신하는 서버는 별도의 데이터베이스 조회 없이도 토큰 내의 정보만으로 요청을 처리할 수 있다.




2. JWT의 구조

JWT는 마침표(.)를 구분자로 하여 세 가지 부분으로 나뉜다. 각 부분은 Base64Url 방식으로 인코딩되어 하나의 문자열을 형성한다.


2-1. Header

헤더는 토큰에 대한 메타데이터를 담고 있다. 일반적으로 두 가지 정보를 포함한다.


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

2-2. Payload (페이로드)

페이로드에는 전달하고자 하는 실제 정보인 Claim 이 포함된다.

{
    "name": "Hong",
    "email": "Hong@example.com",
}

Claim 은 크게 세 가지 종류로 구분


2-3. Signature

Signature 는 토큰의 무결성을 증명하는 핵심 부분이다. 인코딩된 헤더와 페이로드를 합친 뒤, 서버가 안전하게 보관 중인 Secret Key 를 사용하여 헤더에 명시된 알고리즘으로 해싱한다. 이를 통해 서버는 전달받은 토큰이 위변조되지 않았음을 검증할 수 있다.




3. 인증 방식의 변화: 세션 기반 vs 토큰 기반

로그인 상태를 유지하는 방식은 서버의 상태 저장 여부에 따라 크게 두 가지로 나뉜다.


3-1. Stateful → 세션

전통적인 세션 방식은 서버가 사용자의 상태를 메모리나 데이터베이스에 유지한다.


3-2. Stateless → JWT

JWT는 서버가 상태를 저장하지 않는 Stateless 아키텍처를 지향한다.

구분 세션/쿠키 방식 JWT 방식
저장 위치 서버(Memory/DB) 및 클라이언트 쿠키 클라이언트 (Local Storage/Cookie)
확장성 낮음 (세션 동기화 필요) 높음 (어느 서버에서나 검증 가능)
보안성 세션 ID 탈취 시 위험하지만 서버 제어 가능 토큰 탈취 시 만료 전까지 무방비 상태


4. 보안 강화를 위한 Access & Refresh Token

이를 위해 Access TokenRefresh Token 을 병행하는 전략이 사용된다. 이 방식을 통해 사용자는 빈번한 로그인 없이 서비스를 이용할 수 있으며, 서버는 Refresh Token 을 검증하거나 차단함으로써 사용자의 접속을 제어할 수 있는 수단을 갖게 된다. 최근에는 보안성을 더 높이기 위해 Refresh Token 을 한 번 사용하면 폐기하고 재발급하는 방법도 사용하고 있다.




5. JWT와 쿠키

쿠키와 JWT는 사실 완전히 상이한 개념이다.




6. JWT 토큰 보관 장소?

그렇다면 클라이언트에서 토큰을 어디에 저장하는게 좋을까? 브라우저의 로컬 스토리지에 담을 수도 있고, 쿠키에 담아 보관할 수도 있다.


6-1. Local Storage


// HTTP 응답
HTTP/1.1 200 OK
Content-Type: application/json

{
  "token": "eyJhbGci...",
  "username": "hong"
}

JWT 토큰을 로컬 스토리지에 보관하기 위해서는, 백엔드가 Response Body에 토큰을 담아보내면 된다. 그러면 프론트에서 토큰을 받아 로컬스토리지에 저장하면 된다.



// 백엔드 (Cookie 방식)
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request, 
                                HttpServletResponse response) {
    // 인증 처리
    String token = jwtTokenProvider.createToken(username);

    // 쿠키로 토큰 전달
    Cookie cookie = new Cookie("jwt", token);  // 쿠키에 담아서 줌
    cookie.setHttpOnly(true);   // JS 접근 차단
    cookie.setSecure(true);     // HTTPS만
    cookie.setMaxAge(3600);     // 1시간
    cookie.setPath("/");
    response.addCookie(cookie);

    return ResponseEntity.ok(new LoginResponse("로그인 성공"));
}

JWT 토큰을 쿠키에 저장하기 위해서는 백엔드에서 보낼 때 Cookie 객체에 담아서 보내면 된다. 보안을 위한 몇가지 설정을 하고 쿠키 객체에 담아서 보내면 프론트에서 추가작업 없이 자동적으로 브라우저의 쿠키영역에 토큰이 저장된다.



6-3. 보관 방법 선택

그래서 어디에 저장하는게 좋을까?

차이점 정리

구분 Local Storage HttpOnly Cookie
XSS 공격 취약 (JS 접근 가능) 안전 (HttpOnly시 JS 접근 불가)
CSRF 공격 안전 취약 (자동 요청)
용량 제한 약 5MB 약 4KB

Local Storage를 선택하는 경우

요즘 어떤걸 쓰나 보니까

이렇게 하면 XSS로 Access Token이 털려도 금방 만료되어 피해가 적고, 핵심인 Refresh Token은 자바스크립트가 접근할 수 없어 안전하게 보호 가능!




7. Spring의 몫 vs 개발자의 몫

7-1. Spring Security에서 제공하는 것


7-2. 개발자가 만들어야 하는 것




7. 추가 질문

session과 쿠키의 발전과정?

세션도 있는데 왜 쿠키가 나오게 된거? 세션인증이 필요한

8. 결론

JWT란?


JWT vs Session 인증


Spring에서 JWT 사용 전개

// 로그인
POST /login → 토큰 생성 → "eyJhbG..." 반환

// 이후 요청  
GET /api/posts + Header(토큰) → Filter에서 검증 → Controller



9. Reference