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

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

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

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

Java

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

受付中

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クリップ

455閲覧

投稿2022/05/18 12:30

編集2022/05/19 10:38

実現したいこと

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

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

実行結果は以下のようになってしまいます。
・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

import java.math.BigInteger; import java.util.Base64; import java.security.KeyFactory; import java.security.Signature; import java.security.PrivateKey; import java.security.SignatureException; import java.security.NoSuchAlgorithmException; import java.security.spec.RSAPrivateCrtKeySpec; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; public class SHA256withRSA { /** * RSASSA-PKCS1-v1_5 with SHA-256によるデジタル署名の生成 */ public static void main(String args[]) throws Exception{ String header_local = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; String payload_local = "{\"iss\":\"{クライアントID}\",\"sub\":\"{サービスアカウントID}\",\"iat\":1652875817,\"exp\":1652878217}"; String headerEncoded = Base64.getEncoder().encodeToString(header_local.getBytes()); String payloadEncoded = Base64.getEncoder().encodeToString(payload_local.getBytes()); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] keyContentAsBytes = Base64.getDecoder().decode("{改行等を除去した秘密鍵本体}"); PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(keyContentAsBytes); String tempAccessToken = headerEncoded+"."+ payloadEncoded; try { RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privSpec); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(privKey); sign.update(tempAccessToken.getBytes()); byte[] signatureBytes = sign.sign(); String jsonToken = Base64.getUrlEncoder().encodeToString(signatureBytes); String JWTtoken = tempAccessToken + "." + jsonToken; System.out.println("JWT = " + JWTtoken);; } catch (InvalidKeySpecException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SignatureException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

実行結果
イメージ説明

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

良い質問の評価を上げる

以下のような質問は評価を上げましょう

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

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

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

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

JWT(JSON Web Token)

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

Java

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