세션과 JWT을 다루기 전에 먼저 인증(Authentication)과 인가(Authorization)에 대해서 알아야 한다.
1. 인증(Authentication)과 인가(Authorization)

인증은 쉽게 말해 로그인이라고 생각하면 된다.
내가 이 사이트에 가입된 회원임을, 즉 특정 서비스에 일정 권한이 주어진 사용자임을 아이디와 패스워드 등을 통해 인증하는 것이다.
인가는 이렇게 한 번 인증을 받은 사용자가 이후 서비스의 여러 기능들을 사용할 때,
예를 들어 구글 이메일에 로그인한 후 보낸 메일함이나 스팸 메일함 등을 보는 것처럼,
내 계정으로만 할 수 있는 활동을 할 때, 서버가 이 사용자가 로그인되어 있음을 식별하고 허가해주는 과정이다.
즉, 로그인이 유지되는 상태에서 일어나는 동작이라고 보면 된다.
정리하면, 인증은 사용자가 본인의 계정임을 증명하고 로그인하는 과정이고,
인가는 인증을 마친 사용자가 서비스 내에서 기능을 사용할 때, 서버가 그 사용자를 로그인을 한 사용자 라는 것을 알아보고(인식) 허용해주는 과정이다.
세션과 JWT는 인증 이후의 인가를 관리하고 처리하기 위한 기술이다.
2. 이런 기술이 왜 필요할까?
지금 이 순간에도 많은 사람들이 한 사이트에 접속해 여러 서비스를 이용하고 있다.
웹사이트 상의 링크나 버튼을 클릭하는 것 하나하나가 모두 서버로의 요청이며,
서버는 이처럼 동시다발적으로 들어오는 수많은 사용자들의 요청에 실시간으로 응답하고 있다.
이 사용자들 중에는 로그인한 상태의 사용자도 있고, 그냥 방문만 한 사용자도 있다.
서버는 각 요청이 들어올 때마다, 요청을 보낸 사용자가 로그인, 즉 인증을 완료한 상태인지 확인하고,
그에 따라 이메일 열람, 댓글 작성 등 로그인한 사용자만 이용할 수 있는 기능들을 허용할 지 결정해 응답해야 한다.
문제는 매번 요청이 올 때마다 인증 과정을 전부 처리하는 것은 매우 비효율적이라는 점이다.
예를 들어, 요청마다 데이터베이스에서 사용자 계정의 해시값을 불러오고,
그 값이 암호를 복잡한 알고리즘으로 계산한 결과와 일치하는지 확인하는 과정을 거친다면
시간과 자원을 많이 소모하게 되고, 동시에 보안적인 위험도 커진다.
이러한 문제를 해결하기 위해,
사용자가 로그인한 상태라는 사실을 서버가 인지할 수 있도록 유지하는 방법이 필요하며,
그 대표적인 방식이 바로 세션과 JWT이다.
3. 세션 (Session)
사용자가 로그인에 성공하면, 서버는 고유한 세션 ID를 생성한다.
이 세션 ID는 클라이언트(브라우저)와 서버에 보내진다.
서버에서는 사용자 정보와 함께 메모리나 저장소에 보관하지만, 경우에 따라 하드디스크나 데이터베이스에 저장되기도 한다.
브라우저는 전달받은 세션 ID를 쿠키에 저장하고, 이후 사이트에 요청을 보낼 때마다 해당 세션 ID를 함께 전송한다.
서버는 요청에 담긴 세션 ID를 확인하여, 세션 저장소에 해당 ID가 존재하면 인증된 사용자임을 인식하고 인가를 처리한다.
이처럼 세션 ID를 통해 서버가 로그인 상태를 인식하고 유지하는 방식을 세션 기반 인증이라고 한다.

3.1 단점
세션은 서버 메모리에 사용자 정보를 저장하기 때문에 서버가 재부팅되면 메모리에 있던 세션 정보가 모두 사라지고,
사용자들은 로그인 상태를 잃게 되어 다시 로그인해야 하는 상황이 발생할 수 있다.
또한 사이트 규모가 커져 여러 대의 서버로 구성될 경우, 서버 간 세션 정보가 공유되지 않으면 인증이 끊어지는 문제가 발생한다.
예를 들어, 로그인 요청은 1번 서버에서 처리했지만, 이후 요청이 3번 서버로 전달되면
3번 서버에는 해당 세션 ID 정보가 없기 때문에 로그인 상태를 유지할 수 없게 된다.
이를 해결하기 위해 세션 정보를 공용 데이터베이스나 Redis, Memcached 같은 인메모리 저장소에 저장해
모든 서버가 세션 정보를 공유하도록 구성하기도 한다.
하지만 이처럼 서버가 사용자의 상태를 기억해야 하는 구조는 복잡하고 유지 관리가 어렵다.
이러한 구조적 부담 없이 인증 상태를 유지할 수 있도록 고안된 방식이 바로 토큰 기반 인증인 JWT이다.
4. JWT (JSON Web Token)
JWT는 사용자가 로그인을 하면, 서버가 별도로 상태를 저장하지 않고 토큰을 클라이언트에게 직접 발급하는 방식이다.
즉, 세션처럼 서버가 로그인 상태를 기억하지 않는(stateless) 구조이다.

4.1 구성 요소
JWT는 3개의 인코딩된 문자열을 점(.)으로 이어붙인 구조로 되어 있다.
구성 요소는 Header, Payload, verify Signature이다.
Header를 디코딩하면 두 가지 정보가 담겨있다.
- type: 토큰의 타입, JWT이므로 JWT라고 적혀있다.
- alg: Signature를 생성할 때 사용할 해시 알고리즘 (HS256 등 암호화 방식 중 하나)
Header와 Payload, 그리고 서버에 감춰놓은 비밀 값을 이 암호화 알고리즘에 넣고 돌리면 Signature 값이 나온다.
Payload는 Base64로 인코딩된 JSON 데이터로,
토큰 발급자(iss), 수신자(sub), 만료 시간(exp), 발급 시간(iat) 등의 정보가 담겨 있다.
이러한 정보를 Claim이라고 부르며, 사용자 정보나 권한 등의 데이터를 담을 수 있다.
Signature는 Header와 Payload를 서버의 비밀 키와 함께 암호화 알고리즘에 넣어 계산한 결과이다.
이 Signature 덕분에 Payload가 위조되지 않았는지 검증할 수 있다.
4.2 동작 방식
클라이언트가 서버에 요청을 보낼 때, JWT는 HTTP 요청의 Authorization 헤더에 담겨 전송된다.
서버는 전달받은 JWT에서 Header와 Payload를 꺼내고, 자신이 갖고 있는 비밀 키를 이용해 다시 Signature를 계산한다.
- 만약 클라이언트가 보낸 Signature와 계산한 결과가 일치한다면 → 조작되지 않은 유효한 토큰이다.
- Signature가 일치하지 않거나, 만료 시간이 지났다면 → 요청은 거부된다.
이러한 과정을 통해 서버는 요청자가 인증된 사용자임을 판단하고 인가를 수행한다.
4.3 단점
JWT의 큰 단점은 한번 발급된 토큰을 서버가 "통제"할 수 없다는 점이다.
이미 클라이언트에게 발급된 토큰은 서버가 강제로 폐기하거나 무효화할 수 없다.
만약 이 토큰이 해커에게 탈취된다면, 유효기간이 끝나기 전까지는 누구든 사용할 수 있다.
이 때문에, 실제 서비스에서는 JWT만으로 인가를 처리하는 경우는 많지 않다.
4.4 보완 방법: Access Token + Refresh Token 구조
이 문제를 보완하기 위해 사용하는 방식이 Access Token과 Refresh Token을 함께 사용하는 방식이다.
- Access Token: 몇 분 ~ 몇 시간으로 유효기간이 짧고, 실제 API 요청에 사용된다.
- Refresh Token: 2주 정도로 유효기간이 길고, Access Token을 재발급받는 용도로 사용된다.
Refresh Token은 클라이언트에 저장되며, 서버 측에도 저장하여 일치 여부를 확인하는 방식으로 관리한다.
Access Token이 만료되었을 때, 클라이언트는 Refresh Token을 서버에 전송하고,
서버는 DB에 저장된 Refresh Token과 일치 여부를 검증해 새 Access Token을 발급한다.
이때 Refresh Token만 잘 관리하면,
사용자는 유효할 동안은 Access Token이 만료될 때마다 다시 로그인하지 않아도 토큰을 갱신할 수 있다.
강제 로그아웃을 하려면, 서버가 Refresh Token을 삭제하여 더 이상 Access Token을 갱신하지 못하게 막으면 된다.
하지만 Access Token이 탈취당했을 경우, 유효기간이 끝나기 전까지는 차단할 방법이 없기 때문에 이 구조 역시 완벽하지는 않다.
'Web' 카테고리의 다른 글
[Web] SPA? MPA? CSR? SSR? SSG? (1) | 2025.03.22 |
---|---|
[Web] Webpack이란 무엇일까? (1) | 2024.12.14 |
[Web] 모듈 번들러, 한 페이지로 끝내기 (2) | 2024.12.13 |
[Web] CORS 에러는 왜????? 발생하는 걸까? (1) | 2024.12.12 |