実現したいこと
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}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。