JWT(JSON Web Token)는 두 개체에서 JSON 객체를 사용하여 가볍고 자가수용적인 방식으로 정보를 안정성 있게 전달해준다.
기본적은 인증을 진행하는 구조는 Cookie때와 크게 다르지는 않지만, 가장 큰 차이점은 JWT는 서명된 토큰 이라는 점이다.
공인/개인 키를 쌍으로 사용하여 토큰에 서명할 경우 서명된 토큰은 개인 키를 보유한 서버가 이 서명된 토큰이 정상적인 토큰인지 인증한다.
JWT는 .
을 구분자로 3가지의 문자열로 구성되어 있다.
aaa.bbb.ccc
의 구조로 앞에서 부터 헤더(header)
, 내용(payload)
, 서명(signature)
로 구성된다.
Header
에는 토큰의 타입, 서명 생성에 어떤 알고리즘이 사용되었는지 저장한다.
{
"typ" : "JWT",
"alg" : "HS256"
}
Payload
부분에는 토큰을 담을 정보가 들어있다. 정보의 한 조각은 클레임(claim)이라 불리고, 이는 키-밸류의 한 쌍으로 이루어져 있다.
⚠️ payload에 민감한 정보를 담아선 안된다. 특별한 암호화가 되어있지 않기 때문에 누구나 jwt를 디코딩 한다면 payload안에 담긴 값을 알 수 있다.(header도 마찬가지다.)
등록된(registered) 클레임
등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기 위해 이름이 이미 정해진 클레임이다.
iss(발급자), exp(만료 시간), sub(제목), aud(대상), 기타 등등... 이 있다.
공개(public) 클레임
공개 클레임들은 충돌이 방지된 이름을 가지고 있어야 한다. 충돌 방지를 위해 URI형식으로 짓는다.
비공개(private) 클레임
등록된 클레임, 공개 클레임이 아니다. 당사자 간에 정보를 공유하기 위해 생성된 클레임이다.
Signature
는 헤더의 인코딩값과 정보의 인코딩값을 합친후 주어진 비밀키로 해쉬를 하여 생성한다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
header를 디코딩한 값, payload를 디코딩한 값을 위처럼 합치고 이를 서버가 갖고 있는 개인키로 암호화를 한다.
따라서 서명은 서버에 있는 개인키로만 암호화를 풀 수 있기때문에, 다른 클라이언트는 임의로 복호화할 수 없다.