
JWTをPythonでゼロからつくる|ログイン認証トークンのしくみ
2026-09-12 ・ 実践
ログイン状態を保つ仕組みとして、いまや定番の JWT(JSON Web Token)。この記事では中身をブラックボックスにせず、Pythonの標準ライブラリだけでゼロから実装します。作ってみると「なぜ改ざんできないのか」がはっきりわかります。
JWTの3つのパーツ
JWTは ヘッダ.ペイロード.署名 の3つを.で繋いだ文字列です。
3パーツをドットで連結
ヘッダ
署名方式など
ペイロード
ユーザーID等
署名
改ざん検知
準備
標準ライブラリ(hmac・hashlib・base64・json)だけ。
① JWTを発行する
ヘッダとペイロードをBase64URLで符号化し、秘密鍵でHMAC署名します。
import hmac, hashlib, base64, json
SECRET = b"my-server-secret"
def b64(data: bytes) -> str:
return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
def make_jwt(payload: dict) -> str:
header = {"alg": "HS256", "typ": "JWT"}
h = b64(json.dumps(header).encode())
p = b64(json.dumps(payload).encode())
signing_input = f"{h}.{p}".encode()
sig = hmac.new(SECRET, signing_input, hashlib.sha256).digest()
return f"{h}.{p}.{b64(sig)}"
token = make_jwt({"user_id": 42, "role": "admin"})
print(token)
② 検証する(改ざん検知)
同じ手順で署名を作り直し、一致するか確かめます。
def verify_jwt(token: str):
h, p, s = token.split(".")
expected = hmac.new(SECRET, f"{h}.{p}".encode(), hashlib.sha256).digest()
if not hmac.compare_digest(b64(expected), s): # タイミング攻撃対策
return None
pad = "=" * (-len(p) % 4)
return json.loads(base64.urlsafe_b64decode(p + pad))
print("正規:", verify_jwt(token))
# ペイロードを role=admin に改ざんしてみる
h, p, s = token.split(".")
fake_p = b64(json.dumps({"user_id": 42, "role": "superadmin"}).encode())
print("改ざん:", verify_jwt(f"{h}.{fake_p}.{s}"))
出力は正規なら中身が返り、改ざんはNone(検証失敗)。ペイロードを書き換えても、秘密鍵を知らなければ正しい署名を作れないので即バレます。
ペイロードは『暗号化』ではない
JWTのペイロードはBase64で誰でもデコードできます(暗号化ではない)。だからパスワードなど秘密情報は入れないこと。JWTが守るのは「改ざんされていないこと」であって「中身の秘匿」ではありません。
有効期限を必ず入れる
実務では exp(有効期限)をペイロードに入れ、検証時に期限切れを弾きます。盗まれたトークンが永久に使えるのを防ぐためです。本番では実績あるライブラリ(PyJWTなど)の利用を推奨します。
まとめ
- JWTは
ヘッダ.ペイロード.署名の3構造 - 署名はHMAC。秘密鍵を知らないと正しい署名を作れない=改ざん検知
- 検証は
hmac.compare_digestでタイミング攻撃を防ぐ - ペイロードは暗号化ではない。秘密情報は入れず、
expで期限を付ける
もう少し詳しく(背景と理論)
JWT(JSON Web Token)は RFC 7519 で定義される、署名付きの自己完結型トークンです。ヘッダ・ペイロード・署名の3部をドット区切りでBase64URLエンコードします1。最も有名な脆弱性が alg: none 攻撃——署名アルゴリズムを「なし」に改ざんして検証を無効化する手口で、検証側は許可アルゴリズムを固定してこれを防ぎます2。また対称鍵(HS256)と公開鍵(RS256)のアルゴリズム取り違え攻撃にも注意が要ります。ペイロードは暗号化されず誰でも読めるため、パスワード等の秘密は入れないこと、exp(有効期限)を必ず設定すること、失効はサーバー側の管理が必要なことが実務の鉄則です3。
次の一歩 🌸
署名の基礎はHMACで署名・検証、パスワード保存はパスワードハッシュ、多要素認証はMFAへどうぞ。