본문 바로가기
개발

JWT 토큰 인증방법에 대해

by owel.dev 2025. 6. 29.

JWT 토큰이란?

JWT 토큰은 Json Web Token의 약자로, 웹 통신시 클라이언트의 인증에 사용되는 JSON 형태의 토큰 값입니다.

JWT토큰은 서버측에서 토큰 값의 검증에 대해 DB 조회가 필요 없어 효율적이라는 장점이 있습니다.

JWT 토큰의 구조

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiJ1c2VyQGV4YW1wbGUuY29tIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3NTA4MjYyODgsImlhdCI6MTc1MDczOTg4OH0
.cSW65JDV0wTpSIfQV4KPE8kWuNmZb6GRCNhX7Kbfq14

JWT토큰은 위의 예시처럼 하나의 긴 Base64URL 문자열로 이루어져 있습니다.

해당 문자열은 "." 문자를 기준으로 3개의 부분으로 나뉘는데 각 부분은 Header, Payload, Signature라 부르며 클라이언트의 인증에 필요한 정보들을 담고있습니다.

Header

/** 
 *	Header부분의 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 를 
 *	Base64URL 포맷으로 디코딩하면 아래와 같은 JSON 문자열이 됨
 */
{
    "alg": "HS256",
    "typ": "JWT"
}

Header에는 토큰에 대한 메타데이터가 담겨있습니다.

alg의 값을 Signature 생성에 사용되는 알고리즘을 나타내며 typ은 토큰의 타입을 나타냅니다.

Payload

/** 
 *	Payload부분의 
 *	eyJzdWIiOiJ1c2VyQGV4YW1wbGUuY29tIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3NTA4MjYyODgsImlhdCI6MTc1MDczOTg4OH0 를 
 *	Base64URL 포맷으로 디코딩하면 아래와 같은 JSON 문자열이 됨
 */
{
    "sub": "user@example.com",
    "roles": [
        "ROLE_ADMIN"
    ],
    "exp": 1750826288,
    "iat": 1750739888
}

Payload에는 클라이언트의 인증에 필요한 신원 정보가 담겨있습니다.

sub은 사용자 식별정보, roles는 사용자 권한 정보, exp는 토큰 만료시간, iat은 토큰 생성시간을 나타냅니다.

Signature

/**
 *	Signature 부분의 cSW65JDV0wTpSIfQV4KPE8kWuNmZb6GRCNhX7Kbfq14 을 
 *	Base64URL 디코딩하면 아래와 같은 해시 문자열이 됨
 */
7125bae490d5d304e94887d057828f13c916b8d9996fa19108d857eca6dfab5e

SIgnature는 토큰이 서버측에서 발급한 것이 맞는지, Header와 Payload 값이 위조되지는 않았는지 검사하는데 사용되는 값입니다.

서버가 클라이언트에게 JWT토큰을 발급할 때 Header, Payload, “서버만 알고있는 비밀 문자열” 을 더하고 Header의 alg의 알고리즘으로 해싱하여 해시값을 생성하는데 이것이 Signature의 값입니다.

이후 서버는 클라이언트에게 받은 JWT토큰을 검증할 때 발급시 Signautre를 생성했던것과 동일한 방법으로

토큰의 Header, Payload의 값과 “서버만 알고잇는 비밀 문자열”을 더하고 Header의 alg 값의 알고리즘으로 해싱하여 새로운 Signature값을 만든 후, 이 값이 토큰의 기존 Signature값과 동일할 경우 해당토큰의 값을 신뢰하고 Payload의 값을 클라이언트의 인증에 사용합니다.

JWT 토큰의 장점과 단점

JWT토큰은 서버측에서 토큰의 Signature를 사용하기에 토큰값의 검증에 DB 조회가 필요없다는 장점이 있는 반면 토큰값 그 자체로만 검증하고 사용하기에 서버측에서 해당 토큰을 무효화하기가 어렵다는 단점이 있습니다.

그렇기에 토큰이 탈취되거나 해당 토큰을 악의적인 요청이 서버측에서 감지됐을때 해당 토큰을 즉시 만료시킬수가 없기에  높은 보안 요구사항이 있을 경우 JWT토큰의 만료시간을 짧게 설정하거나 DB에 별도의 인증정보를 저장하여 사용하는 Session 방식 인증을 사용하는게 좋습니다.

리프레시 토큰의 등장

JWT토큰의 만료시간을 짧게 하여 JWT의 보안상의 단점을 보완할 수 있지만, 만료시간이 짧을수록 사용자가 로그인 등의 방법으로 서버로부터 토큰을 발급받아야 하는 주기가 짧아지기에 사용자의 편의성이 줄어드는 문제는 여전히 남아있습니다.

 

이러한 문제를 해결하기 위해 리프레시 토큰이라는 방법이 등장하였는데, 서버에서 토큰 발급시 기존의 토큰을 엑세스 토큰이란 이름의 토큰으로 만료시간을 짧게 하여 발급하고 리프레시 토큰이라는 이름의 만료시간이 긴 토큰을 추가로 발급합니다.

엑세스 토큰은 기존의 JWT토큰처럼 사용자의 인증에 사용되고 리프레시 토큰은 엑세스 토큰의 만료 시 엑세스 토큰의 재발급에 사용되는 토큰입니다.

엑세스 토큰은 그 자체로 사용 가능하지만 만료시간이 짧게 설정하여 보안성을 높이고, 리프레시 토큰은 토큰 검증시 서버의 DB에 별도의 정보를 저장하여 검증하도록 구축합니다.

 

이렇게 하면 엑세스 토큰 만료시에는 사용자가 다시 로그인을 하지 않더라도 리프레시 토큰을 사용하여 엑세스 토큰을 재발급 받을 수 있고 리프레시 토큰은 만료시간이 길지만 서버측에서 DB를 사용하여 검증하기에 언제든 무효화 할 수 있습니다.

(리프레시 토큰 사용 시 DB검증을 통한 비효율은 일반적인 사용 패턴에서 엑세스 토큰에 비해 리프레시 토큰의 사용빈도는 매우 적다는 사실을 감안하면 그다지 문제가 되지 않습니다.)

리프레시 토큰을 통해 만료시간을 짧게 설정하여 보안성을 높인 엑세스 토큰의 단점을 효과적으로 보완할 수 있습니다.

엑세스 토큰, 리프레시 토큰 실전 사용 사례

클라이언트가 서버에 로그인을 통해 토큰 발급을 요청을 보내면 서버는 엑세스 토큰을 응답 Body를 통해 응답하고

리프레시 토큰은 Set-Cookie 헤더에 보안 쿠키, URL 지정 등 여러 보안 설정과 함께 응답하여 클라이언트의 브라우저 쿠키에 보관되도록 지시합니다.

 

서버의 응답을 받은 클라이언트는 응답 Body의 엑세스 토큰은 자바스크립트 메모리에 보관하여 XSS공격과 CSRF 공격을 원천 방어하며 새로고침이나 세션 종료 등의 상황에서 엑세스 토큰값이 더 자주 만료되도록 해 보안성을 높이고 인증이 필요한 요청시 Authorization Header에 엑세스 토큰값을 담아 서버에 요청을 전달합니다.

 

리프레시 토큰은 서버의 Set-Cookie 응답에 의해 자동으로 클라이언트 브라우저 쿠키에 저장됩니다.

클라이언트는 인증이 필요한 요청에 대해 서버로부터 잘못된 토큰이라는(토큰 만료, 토큰값 없음, 잘못된 토큰 등..) 응답을 받으면 쿠키의 리프레시 토큰에 설정된 리프레시 URL로 쿠키에 담긴 리프레시 토큰값과 함께 요청을 보내어 엑세스 토큰을 다시 발급받은 후 기존에 잘못된 토큰이라는 원인에 의해 거부당한 요청을 다시 서버로 보냅니다.