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

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

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

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

Java

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

Q&A

受付中

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

iii02
pp02

総合スコア4

JWT(JSON Web Token)

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

Java

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

1回答

0グッド

0クリップ

1945閲覧

投稿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による取得結果
イメージ説明

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

0

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

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

投稿2022/05/19 01:38

iii02

総合スコア4

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

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

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

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

JWT(JSON Web Token)

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

Java

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