점(.)으로 분리된 3부분으로 구성 (header, payload, verify signature)
{
"alg": "HS256",
"typ": "JWT"
}
이후 header 부분은 Base64URL로 인코딩된다.
registered claims: iss(issuer), exp(expiration time), sub(subject), aud(audience) and etc. It is not mandatory but recommended.
public claims
private claims
이후 payload는 Base64URL로 인코딩된다. 민감한 정보는 디코딩이 가능하므로 담으면 안된다.
header와 payload가 각각 base64인코딩된 것을 점으로 이어 붙인뒤 본인이 header에 명시한 알고리즘으로 시크릿과 함께 signature를 만든다. 그 후 base64로 인코딩한다.
const secret = "..."
const headerAndPayload = base64UrlEncode(header) + "." + base64UrlEncode(payload);
const signature = crypto.createHmac('sha256', secret).update(headerAndClaimSet).digest('base64')
기존의 토큰방식은 데이터베이스(또는 서버캐시)에 저장하고 유효성을 검사해야했다면, jwt는 토큰만 가지고 유효성검사나 사용자 식별까지 할 수 있으므로 서버를 무상태로 유지하는 것이 가능하다.
클레임셋이 암호화되지 않으므로 민감하지 않은 최소한의 정보만 클레임셋에 담아야한다.
클레임셋의 길이가 길면 토큰의 길이도 길어진다.
토큰이 탈취되면 답이 없다.
여러가지 방법이 있지만 그 중 가장 낫다고 생각하는 방식은 access / refresh token.
Authorization Bearer jwt_token
에 추가해서 보낸다. access token은 쿠키에 저장할 필요가 없으므로 Cross-Origin Resource Sharing (CORS), SameSite 이슈로 부터 자유롭다. Nuxt같은 SSR에서는 API서버와 SameSite가 아닌 경우, Refresh Token이 SameSite 쿠키이기 때문에 token refresh를 Nuxt Server 에서 담당해야한다.