質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

1回答

5041閲覧

JavaでRS256アルゴリズムによるJWTを生成したい

iii02

総合スコア4

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2022/05/18 12:30

編集2022/05/18 15:44

実現したいこと

JavaでRS256アルゴリズムによるJWT電子署名を生成したいと考えています。
現在、java-jwt を用いて実装しようとしています。

手元には、
・BASE64エンコードされたヘッダー情報
・BASE64エンコードされたペイロード情報
・JWT署名のために必要な秘密鍵
がすでに存在するという前提です。

前提

具体的には、こちらのページ(LINEWORKS)の
https://developers.worksmobile.com/jp/reference/authorization-sa?lang=ja
部分のJWT電子署名をJavaで実装したいと考えております。

イメージ説明

発生している問題・エラーメッセージ

プログラム自体は正常に動いてJWTが生成されるのですが、Postmanを用いてLINEWORKS APIを実行しようとするとエラーが発生してしまいます。
そのため、以下の2点を質問させてください。

①string型の秘密鍵を RSAPrivateKey型に変える方法は「該当のソースコード」項目に記載してあるような方法で合っているか?
https://stackoverflow.com/questions/34454531/java-how-can-i-generate-privatekey-from-a-string を参考に作成しました。

こちらのページのようなJWT署名をやりたい場合、 秘密鍵を用いたJWT生成は以下のコードで合っているか?
(最終的なJWTとして、一応それっぽいものは生成されるのですが、Postmanを用いて確認すると「500 Internal Server Error」となり、正しいJWTではないことが予想されます)

一応、ヘッダーとペイロード情報は正常にBASE64エンコードできたことは確認済みです。

該当のソースコード

gradleへのインポート

dependencies { implementation 'com.auth0:java-jwt:3.19.0' }

Java

1//秘密鍵の設定 2String privateKey = {"-----BEGIN PRIVATE KEY-----" と改行、"-----END PRIVATE KEY-----" を除去した秘密鍵}; 3 4//ヘッダーの設定 5Map<String, Object> headerClaims = new HashMap(); 6//ヘッダーのalg と typ は自動で付与されるため何も書かない 7 8//ペイロードの設定 9Map<String, Object> payloadClaims = new HashMap<>(); 10payloadClaims.put("iss", "Client ID"); 11payloadClaims.put("sub", "Service Account"); 12payloadClaims.put("iat", "JWT生成日時"); 13payloadClaims.put("exp", "JWT満了日時"); 14 15KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 16byte[] keyContentAsBytes = Base64.getDecoder().decode(privateKey); 17PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(keyContentAsBytes) 18//RSA256を用いた電子署名 19try { 20 RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privSpec); 21 Algorithm algorithm = Algorithm.RSA256(null, privKey); 22 String token = JWT.create() 23   .withHeader(headerClaims) 24   .withPayload(payloadClaims) 25 .sign(algorithm); 26System.out.println("JWT = " + token ); 27} catch (JWTCreationException exception){ 28 //Invalid Signing configuration / Couldn't convert Claims. 29}

実行結果は以下のようになってしまいます。
・JWT自体はエラーが起きずに生成される
イメージ説明

・200 OK が表示されない
イメージ説明
申し訳ありませんがどなたかご教授お願い致します。

試したこと

Linux環境では以下のコマンドですぐに実行できるのですが・・

echo -n '{BASE64エンコードされたヘッダー}.{BASE64エンコードされたペイロード}' | openssl dgst -sha256 -sign privateKey.key -binary | base64

追記

こちらのサイトを参考に、以下のコードをJavaで実行すると正常に動作はするのですが、Postmanを使ってアクセストークンを取得しようとすると「500 Internal Sever Error」と表示されてしまいます。おそらく正しいJWTが取得できていないものだと思われます。
本来の質問とはズレてしまうのですが、以下のコードでJWTを取得するためにはどこが間違っているのでしょうか?
以下、使用コードです。

Java

1import java.math.BigInteger; 2import java.util.Base64; 3import java.security.KeyFactory; 4import java.security.Signature; 5import java.security.PrivateKey; 6import java.security.SignatureException; 7import java.security.NoSuchAlgorithmException; 8import java.security.spec.RSAPrivateCrtKeySpec; 9 10import java.security.InvalidKeyException; 11import java.security.KeyFactory; 12import java.security.NoSuchAlgorithmException; 13import java.security.Signature; 14import java.security.SignatureException; 15import java.security.interfaces.RSAPrivateKey; 16import java.security.spec.InvalidKeySpecException; 17import java.security.spec.PKCS8EncodedKeySpec; 18 19public class SHA256withRSA { 20 /** 21 * RSASSA-PKCS1-v1_5 with SHA-256によるデジタル署名の生成 22 */ 23 public static void main(String args[]) throws Exception{ 24 25 String header_local = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; 26 String payload_local = "{\"iss\":\"{クライアントID}\",\"sub\":\"{サービスアカウントID}\",\"iat\":1652875817,\"exp\":1652878217}"; 27 28 String headerEncoded = Base64.getEncoder().encodeToString(header_local.getBytes()); 29 String payloadEncoded = Base64.getEncoder().encodeToString(payload_local.getBytes()); 30 31 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 32 byte[] keyContentAsBytes = Base64.getDecoder().decode("{改行等を除去した秘密鍵本体}"); 33 PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(keyContentAsBytes); 34 35 String tempAccessToken = headerEncoded+"."+ payloadEncoded; 36 try { 37 RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privSpec); 38 Signature sign = Signature.getInstance("SHA256withRSA"); 39 sign.initSign(privKey); 40 sign.update(tempAccessToken.getBytes()); 41 byte[] signatureBytes = sign.sign(); 42 String jsonToken = Base64.getUrlEncoder().encodeToString(signatureBytes); 43 String JWTtoken = tempAccessToken + "." + jsonToken; 44 System.out.println("JWT = " + JWTtoken);; 45 } catch (InvalidKeySpecException e) { 46 // TODO Auto-generated catch block 47 e.printStackTrace(); 48 } catch (SignatureException e) { 49 // TODO Auto-generated catch block 50 e.printStackTrace(); 51 } 52 } 53}

実行結果
イメージ説明

Postmanによる取得結果
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決しました。
原因は一番初めの 「privateKey に指定していた秘密鍵が最新のものではない」ことが原因でした。

privateKey を最新の状態にして生成したJWTを用いれば正常にアクセストークンの取得ができることを確認しました(添付画像追加)。
「該当のソースコード」部のコードを貼り付ければJava上でJWTが取得できるので情報共有として残します。
イメージ説明

投稿2022/05/19 01:38

iii02

総合スコア4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問