JWT
개요
JSON Web Token.
흔히 HTTP 통신 간 신원을 제공하기 위해 사용되는 토큰으로, RFC 7519에 정의됐다.
가장 흔하게 사용되는 영역이 OAuth, OIDC 인데, JWT라는 토큰 형식이 이들의 기반이 되어준다고 이해하면 좋다.
이름의 유래가 굉장히 단순한데, 그냥 웹 환경에서 JSON 형식으로 만들어진 토큰이라서 JWT이다.
https://jwt.io/
위 사이트가 jwt 토큰을 쉽게 분석해볼 수 있는 사이트로 매우매우 유명하다.
구조
JWT 토큰은 위와 같이 세 부분으로 나뉘며, 각 부분은 base64로 인코딩된다.[1]
일단 헤더와 페이로드가 있는데, 그 값들을 합쳐서 개인키로 암호화한 값을 서명 부분에 달아둔다.
이 토큰을 받은 대상은 공개키로 서명 부분은 복호화해보고 헤더와 내용이 위변조됐는지 확인할 수 있다.
즉, JWT는 어떠한 내용을 담고, 이 내용이 신뢰되는 주체로부터 서명 받은 것을 인증하는데 가장 큰 목적을 둔다.
헤더는 그냥 암호화 방식이랑 유형을 간단하게 나타내고 실제 내용은 페이로드에 전부 들어간다고 보면 된다.
Payload
페이로드 부분에는 임의의 내용을 때려박을 수 있는데, 이때 각 필드를 claim이라고 부른다.
이 토큰이 어떤 내용을 담고 있다, 주장(claim)을 하는 것이기 때문에 이리 부른다고 한다(gpt 피셜).
그래도 조금 RFC로 규정된 형태의 필드들이 있긴 하다.
- iss(Issuer) - 토큰 발행자
- sub(Subject) - 토큰의 주체
- aud(Audience) - 토큰 대상
- 보통 리스트로 주어진다.
- exp(Expiration) - 토큰 만료 시간
- nbf(Not Before) - 토큰 활성화 전 시간
- iat(Issued At) - 발행된 시간
- jti(JWT ID) - 토큰 고유 식별자
뭐.. 이렇긴 한데 사실 이거 다 쓰는 토큰을 거의 본 적이 없다.
그리고 이거 말고도 임의의 클레임을 넣어도 상관이 없어서 그걸 활용하는 케이스가 대부분이기도 하다.
표준이지만 너무 나이브한 표준인
JWE? JWS? JWKS?
JWT와 관련해서 나오는 몇 가지 개념들이 추가적으로 있다.
사실 JWT는 이런 식으로 만든 토큰 인터페이스라고 보면 된다.
이걸 실제 토큰으로 구현할 때는 두 가지 방식이 존재한다.
- JSON Web Signature - 위에서 본 방식을 말한다.
- JSON Web Encryption - 헤더와 페이로드를 통짜로 암호화한 형식을 말한다.
{{header}}.{{encrypted-key}}.{{iv}}.{{ciphertext}}.{{tag}}
- 이런 식으로 생겼다고 하는데, 나는 아직 본 적이 없다.[2]
- 암복호화에 시간이 걸려서 그런 듯?
그러니 흔히 JWT라고 하면 JWS 형식이라고 보면 되겠다.
그렇다면 JWKS는 무엇인가?
https://<server_domain>/.well-known/jwks.json
JSON Web Key Set은 서명된 값을 확인하는 데 사용되는 키 집합을 말한다.
받은 JWT토큰을 검증하기 위해서는 암호화할 때 사용된 몇 가지 값을 알아야 한다.
그래서 보통 암호화를 한 주체는 해당 값들을 알 수 있도록 위의 경로를 노출한다.
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "1"
},
{
"kty": "RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB",
"alg": "RS256",
"kid": "2011-04-29"
}
]
}
대체로 위 경로에는 이런 식으로 값이 담겨 있으며, 이를 기반으로 JWT를 검증하려는 측은 위변조 유무를 파악할 수 있다.[3]
디코딩
jwtd () {
local input="${1:-}"
if [ -z "$input" ]; then
if [ ! -t 0 ]; then
input=$(cat /dev/stdin)
else
echo >&2 '✗ Need an argument or have a piped input!'
return 1
fi
fi
echo "$input" \
| jq -Rrce 'split(".")[1] | . + "=" * (. | 4 - length % 4)' \
| openssl base64 -d -A \
| jq .
}
간단하게 사용할 수 있는 쉘 스크립트를 만들어준 분이 있다.[4]
이걸 rc 파일에 넣건, 그냥 source를 하건 해서 파이프라인으로 전달하거나 jwt를 뒤에 박으면 된다.
아니면 위에 본 사이트를 이용해도 좋다.
관련 문서
이름 | noteType | created |
---|---|---|
OAuth | knowledge | 2025-05-09 |
5W - 이스티오 JWT 인증 | published | 2025-05-11 |