</>DevTools

SGNJWT 토큰 생성기

JSON payload와 secret으로 HS256 서명된 JWT 토큰 생성

HS256
HMAC-SHA256 (대칭키)
권장: 256비트(32바이트) 이상의 랜덤 문자열을 사용하세요.

HS256으로 JWT 서명하기: 개발·테스트용 토큰 만들기

이 도구는 JSON 페이로드와 비밀키를 받아 HS256(HMAC-SHA256)으로 서명된 JWT를 만듭니다. API를 개발하면서 인증이 걸린 엔드포인트를 curl로 찔러 보거나, 만료 처리 로직을 테스트하려고 이미 지난 exp를 가진 토큰을 만들 때 유용합니다. 반대로 하지 말아야 할 일도 분명합니다. 운영 환경의 실제 비밀키를 여기에 넣는 것입니다.

HS256이 하는 일

HS256은 대칭키 방식입니다. base64url(header) + "." + base64url(payload) 문자열에 비밀키를 적용해 HMAC-SHA256 값을 계산하고, 그 결과를 base64url로 인코딩해 세 번째 조각으로 붙입니다. 같은 비밀키를 가진 쪽만 같은 서명을 만들 수 있으므로, 검증하는 쪽도 발급하는 쪽과 동일한 비밀키를 알아야 합니다.

이 점이 HS256의 한계이기도 합니다. 토큰을 검증해야 하는 서비스가 여러 개라면 모두가 같은 비밀키를 공유해야 하고, 그중 하나가 유출되면 전부가 위조 가능해집니다. 검증 주체가 여럿이라면 개인키로 서명하고 공개키로 검증하는 RS256이나 ES256이 적합합니다.

알고리즘키 방식적합한 상황
HS256비밀키 하나를 공유발급자와 검증자가 같은 서비스일 때
RS256개인키로 서명, 공개키로 검증여러 서비스가 검증, OIDC/JWKS 환경
ES256타원곡선 기반, 서명 길이가 짧음RS256과 같은 구조에 토큰 크기를 줄이고 싶을 때

사용 방법

  1. 페이로드에 넣을 JSON을 작성합니다. sub, exp 같은 표준 클레임을 쓰면 라이브러리 호환성이 좋습니다.
  2. 비밀키를 입력합니다. 테스트용이라면 아무 문자열이나 쓸 수 있지만, 아래의 키 길이 항목을 참고하세요.
  3. 생성된 토큰을 복사해 Authorization: Bearer <토큰> 헤더에 사용합니다.
  4. 만료 테스트가 필요하면 exp에 과거 시각의 Unix 초 값을 넣어 만료된 토큰을 만듭니다.

exp와 iat를 정확히 쓰기

exp와 iat는 UTC 기준 Unix 시각을 초 단위로 적습니다. JavaScript의 Date.now()는 밀리초를 반환하므로 1000으로 나누고 소수점을 버려야 합니다. 이 변환을 빠뜨려 exp가 1000배 큰 값이 되면, 만료가 서기 5만 년 뒤로 설정되어 사실상 영구 토큰이 됩니다. 실제로 흔히 발생하는 실수입니다.

올바른 시각 계산
const now = Math.floor(Date.now() / 1000);

const payload = {
  sub: "user-1234",
  iat: now,
  exp: now + 60 * 15,   // 15분 후
  // 만료 테스트용이라면:
  // exp: now - 60,     // 1분 전 = 이미 만료
};

비밀키 길이가 중요한 이유

HMAC-SHA256의 보안 강도는 비밀키의 엔트로피에 좌우됩니다. secret 이나 mysecretkey 같은 짧은 단어를 키로 쓰면, 공격자가 토큰 하나만 확보한 뒤 사전 공격으로 키를 알아낼 수 있습니다. 키를 알면 임의의 페이로드에 유효한 서명을 붙일 수 있으므로, 관리자 권한을 담은 토큰을 마음대로 만들 수 있게 됩니다.

RFC 7518은 HS256의 키가 해시 출력 길이와 같거나 그 이상, 즉 최소 256비트(32바이트)여야 한다고 규정합니다. 실무에서는 무작위 32바이트를 생성해 Base64로 표현한 값을 환경변수에 두는 방식이 일반적입니다.

충분한 강도의 키 생성
# Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

# OpenSSL
openssl rand -base64 32

발급 시 함께 결정해야 할 것들

  • 만료 시간: 액세스 토큰은 짧게(5~30분) 두고 리프레시 토큰으로 갱신하는 구조가 표준입니다.
  • aud(대상): 여러 API가 같은 발급자를 신뢰한다면 aud를 넣어 토큰이 엉뚱한 API에 재사용되는 것을 막습니다.
  • iss(발급자): 검증 시 발급자를 확인하면 다른 시스템의 토큰이 흘러드는 것을 차단합니다.
  • jti: 일회성 토큰이나 강제 무효화가 필요하다면 고유 ID를 넣어 서버에서 추적합니다.
  • 권한 정보의 양: 역할 하나 정도는 넣어도 좋지만, 세밀한 권한 목록을 넣으면 토큰이 커지고 권한 변경이 즉시 반영되지 않습니다.

자주 묻는 질문

여기에 운영 비밀키를 입력해도 되나요?
권장하지 않습니다. 서명 계산은 브라우저에서만 이루어지고 키가 네트워크로 전송되지는 않지만, 운영 서명 키는 유출되면 모든 사용자를 사칭할 수 있는 최상위 등급의 비밀입니다. 그런 값을 브라우저 입력창에 붙여넣는 습관 자체가 위험합니다. 개발용 키나 임시 키로 테스트하세요.
생성한 토큰이 서버에서 거부됩니다.
확인 순서는 이렇습니다. 첫째, 서버의 비밀키와 여기 입력한 키가 정확히 같은지(앞뒤 공백, 개행 포함). 둘째, 서버가 HS256을 허용하는지 — RS256만 허용하도록 설정된 경우가 많습니다. 셋째, exp가 이미 지났는지. 넷째, 서버가 iss나 aud를 검증하는데 페이로드에 없거나 값이 다른지. 다섯째, Authorization 헤더에 Bearer 접두사와 공백이 정확히 들어갔는지.
페이로드에 넣을 수 있는 데이터에 제한이 있나요?
형식상으로는 유효한 JSON이면 됩니다. 다만 두 가지 실질적 제약이 있습니다. 내용이 누구나 읽을 수 있으므로 비밀 값을 넣을 수 없고, 토큰이 매 요청 헤더에 실리므로 크기가 곧 비용입니다. 헤더 크기 제한(서버에 따라 4~8KB)에 걸리면 요청 자체가 거부되기도 합니다.
RS256 토큰도 만들 수 있나요?
이 도구는 HS256만 지원합니다. RS256은 RSA 키 쌍이 필요하므로, RSA Key Generator 도구로 키를 만든 뒤 서버 측 라이브러리(jose, jsonwebtoken 등)로 서명하는 편이 실제 환경에 가깝습니다.
만료된 토큰을 일부러 만들려면?
exp에 현재보다 작은 Unix 초 값을 넣으면 됩니다. 예를 들어 현재 시각에서 3600을 빼면 한 시간 전에 만료된 토큰이 됩니다. 클라이언트가 401을 받았을 때 리프레시 흐름을 제대로 타는지 검증할 때 유용합니다.
헤더의 typ이나 kid를 바꿀 수 있나요?
이 도구는 표준적인 {"alg":"HS256","typ":"JWT"} 헤더를 사용합니다. kid를 포함한 토큰이 필요하다면 서버 측 라이브러리에서 헤더 옵션을 지정해 발급해야 합니다. 검증 쪽 구현을 테스트할 때는 kid 값을 임의로 바꾼 토큰으로 경로 조작 방어가 되어 있는지 확인해 볼 가치가 있습니다.

💡 참고: 테스트가 끝난 임시 토큰은 버전 관리 시스템이나 이슈 트래커에 남기지 마세요. 만료가 길게 설정된 토큰이 저장소에 커밋되어 사고로 이어지는 사례가 많습니다.

🔗관련 도구🔐 암호화/보안