JWT:構造、生成、検証
JWTの構造を手動でデコードし、秘密鍵で署名付きトークンを作成して、フレームワークを使わずにクレームを検証します。
「JWT:構造、生成、検証」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
JWT とは
JSON Web Token(JWT)は、当事者間でクレームを送信するための、コンパクトで URL セーフなトークン形式です。JWT には署名が付けられ、必要に応じて暗号化もされます。自己完結型であるため、クレームの検証にデータベース照会は必要ありません。
JWT の構造: Header.Payload.Signature
JWT は、ドットで区切られた 3 つの Base64URL エンコード部分で構成されます。header.payload.signature の形式です。ヘッダーにはアルゴリズムが指定され、ペイロードにはクレームが含まれます。署名によって完全性を検証します。
// Example JWT:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 <- header
// .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0 <- payload
// .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c <- signatureデコードしたヘッダーとペイロード
各部分を Base64URL でデコードすると、JSON を確認できます。ペイロードにはクレームが含まれます。標準的なクレームには、sub(サブジェクト)、iss(発行者)、exp(有効期限)、iat(発行時刻)があります。
// Header:
{ "alg": "HS256", "typ": "JWT" }
// Payload:
{ "sub": "user-42", "name": "Alice", "role": "ADMIN",
"iat": 1716000000, "exp": 1716003600 }JWT を手動で作成する(HS256)
ヘッダーとペイロードの JSON を作成し、それぞれを Base64URL エンコードしてドットで連結します。次に、header.payload に対して HMAC-SHA256 を計算し、署名として末尾に追加します。
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"sub\":\"user-42\",\"exp\":9999999999}".getBytes());
String sigInput = header + "." + payload;
byte[] sig = computeHmac(secretKey, sigInput);
String jwt = sigInput + "." + Base64.getUrlEncoder().withoutPadding().encodeToString(sig);JWT を手動で検証する
ドットで分割し、ヘッダーとペイロードをデコードします。header.payload に対して HMAC を再計算し、署名と比較して、exp が未来の時刻であることを確認します。
String[] parts = jwt.split("\\.");
String sigInput = parts[0] + "." + parts[1];
byte[] expectedSig = computeHmac(secretKey, sigInput);
byte[] actualSig = Base64.getUrlDecoder().decode(parts[2]);
if (!MessageDigest.isEqual(expectedSig, actualSig)) throw new SecurityException("Invalid signature");
// Decode payload and check exp:
String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]));
// parse JSON and check exp > nowjava-jwt ライブラリを使用する(Auth0)
com.auth0:java-jwt ライブラリを使用すると、流暢な API によって JWT の作成と検証を簡略化できます。
// Create:
Algorithm alg = Algorithm.HMAC256(secretKey);
String token = JWT.create()
.withSubject("user-42")
.withClaim("role", "ADMIN")
.withExpiresAt(Instant.now().plusSeconds(3600))
.sign(alg);
// Verify:
JWTVerifier verifier = JWT.require(alg).withIssuer("my-service").build();
DecodedJWT decoded = verifier.verify(token);
System.out.println(decoded.getSubject());HS256 と RS256
HS256 は共有対称鍵を使用します。単純ですが、発行者と検証者の両方が鍵を信頼して共有する必要があります。RS256 は RSA を使用し、秘密鍵で署名して公開鍵で検証します。署名鍵を知らなくても各サービスが検証できるため、複数サービスのアーキテクチャに適しています。
JWT の保存: HttpOnly Cookie と localStorage
JWT は HttpOnly Cookie に保存します。JavaScript からアクセスできないため XSS による窃取を防止できます。Secure と SameSite=Strict フラグも設定してください。localStorage は避けてください。XSS 攻撃によって読み取られる可能性があります。
// Set JWT as HttpOnly cookie in Spring:
ResponseCookie cookie = ResponseCookie.from("jwt", token)
.httpOnly(true).secure(true).sameSite("Strict")
.path("/").maxAge(3600).build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());リフレッシュトークン
JWT の有効期限は短く設定します(15 分)。リフレッシュトークン(不透明な値で、サーバー側に保存)は、より長い有効期限を持ちます。クライアントは再認証せずに、リフレッシュトークンを新しい JWT と交換します。
JWT の失効に関する課題
JWT はステートレスであり、組み込みの失効機能はありません。有効期限を短く設定し、Redis に失効した JWT ID(jti クレーム)のブロックリストを保持して、有効期限前のログアウトに対応します。
// On logout, add the jti to a Redis blocklist with TTL = token expiry:
redis.set("revoked:" + jti, "1", ex, 3600);
// On verify, check blocklist:
if (redis.exists("revoked:" + decoded.getId())) throw new SecurityException("Token revoked");Spring Security での JWT 統合
Spring Security では、JwtAuthenticationFilter extends OncePerRequestFilter を実装して、各リクエストで JWT を取り出して検証し、SecurityContext に設定します。
String token = request.getHeader("Authorization").replace("Bearer ","");
DecodedJWT decoded = verifier.verify(token);
String userId = decoded.getSubject();
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(auth);確認問題
HS256 と RS256 の JWT 署名における、鍵の構造上の違いは何ですか。
まとめ
JWT は header.payload.signature(Base64URL)で構成されます。HMAC(HS256)または RSA(RS256)で署名します。署名と exp クレームを検証します。HttpOnly Cookie に保存します。有効期限を短く設定し、リフレッシュトークンを使用します。Redis の jti ブロックリストで失効させます。
よくある質問
「JWT:構造、生成、検証」レッスンは無料ですか?
はい。「JWT:構造、生成、検証」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「JWT:構造、生成、検証」で何を学びますか?
JWTの構造を手動でデコードし、秘密鍵で署名付きトークンを作成して、フレームワークを使わずにクレームを検証します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「JWT:構造、生成、検証」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。