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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Authentication

Authentication(認証)は正当性を認証する為の工程です。ログイン処理等で使われます。

Q&A

解決済

1回答

4146閲覧

BOXとAPI連携するためにJWT署名を完了しアクセストークンを取得したい

Xi-wang

総合スコア0

JWT(JSON Web Token)

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Authentication

Authentication(認証)は正当性を認証する為の工程です。ログイン処理等で使われます。

0グッド

0クリップ

投稿2021/12/01 06:37

編集2021/12/02 09:55

前提・実現したいこと

Kintoneのような、Javascriptで機能拡張が可能なWEBデータベースアプリを使用しています。
このアプリ上に、クラウドストレージのBOX
https://www.box.com/ja-jp/home
のAPI機能を使い、UI を表示させたいのですが、API連携に必要なアクセストークンの取得でつまづいています。
処理は全てクライアントのブラウザ上で行われます。非推奨なのは分かっています。

完了したいプロセス
https://ja.developer.box.com/guides/authentication/jwt/without-sdk/

Node.js及びそのライブラリ群やSDKは使用できませんので、下記ライブラリを使用しています。

axios.min.js ($ajaxでもPOST出来ますが、なるべくサンプルの記述に合わせたかったため)
https://github.com/axios/axios

jsrsasign-all-min.js (https://jwt.io/ のライブラリより)
https://github.com/kjur/jsrsasign

querystring.js (ネット上で拾ってきました)

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

ボタンを押すと、UI表示の関数が実行され、その関数の中で、下記getBoxAccessToken()が実行される形となっています。

assertionをPOSTするとエラーが返ります。

assertionを https://jwt.io/ でデバッグすると、signature invalidとなるので、署名が成功していないのですが、原因がどこにあるかわかりません。

POST https://api.box.com/oauth2/token 400 error: "invalid_request" error_description: "Invalid grant_type parameter or parameter missing"

該当のソースコード

JavaScript

1/* getBoxConfig()で取得するconfigの中身 2{ 3 "boxAppSettings": { 4 "clientID": CLIENT_ID, 5 "clientSecret": CLIENT_SECRET, 6 "appAuth": { 7 "publicKeyID": PUBLICK_KEY_ID, 8 "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n...\n-----END ENCRYPTED PRIVATE KEY-----\n", 9 "passphrase": PASS_PHRASE 10 } 11 }, 12 "enterpriseID": ENTERPRISE_ID 13} 14*/ 15 16const getBoxAccessToken = async () => { 17 18 // 読取専用のレコードからコンフィグ情報(JSON)を読み取る 19 let config = await getBoxConfig(); 20 config = JSON.parse(config.Response.Data[0].Body); 21 console.log(config); 22 23 if (!config) { 24 alert('BOX API コンフィグ情報の取得に失敗しました'); 25 return; 26 } 27 28 // 秘密キーをパスコードを使って複合化 29 let prvKey = KEYUTIL.getKey(config.boxAppSettings.appAuth.privateKey, config.boxAppSettings.appAuth.passphrase); 30 31 32 // 認証用URLの定数宣言 33 const authenticationUrl = "https://api.box.com/oauth2/token"; 34 35 // ペイロードを宣言 36 let oPayload = {}; 37 oPayload.iss = config.boxAppSettings.clientID; 38 oPayload.sub = config.enterpriseID; 39 oPayload.box_sub_type = 'enterprise'; 40 oPayload.aud = authenticationUrl; 41 oPayload.jti = KJUR.crypto.Util.getRandomHexOfNbytes(64); 42 oPayload.exp = Math.floor(Date.now() / 1000) + 45; 43 44 let sPayload = JSON.stringify(oPayload); 45 console.log(sPayload); 46 47 // 公開キーIDを格納(使用しない?) 48 let keyId = config.boxAppSettings.appAuth.publicKeyID; 49 50 // ヘッダーを宣言 51 let oHeader = { 52 alg: 'RS256', 53 typ: 'JWT', 54 keyid: keyId 55 } 56 57 let sHeader = JSON.stringify(oHeader); 58 console.log(sHeader); 59 60 // ヘッダー、ペイロードをキー情報を使って署名 61 var assertion = KJUR.jws.JWS.sign('RS256', sHeader, sPayload, prvKey); 62 console.log(assertion); 63 console.log(KJUR.jws.JWS.parse(assertion)); 64 65 // クエリ文字列作成用のオブジェクト宣言 66 let obj = { 67 grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', 68 assertion: assertion, 69 client_id: config.boxAppSettings.clientID, 70 client_secret: config.boxAppSettings.clientSecret 71 } 72 73 // クエリ文字列変換ライブラリを使用してクエリ文字列を生成 74 const query = serialize(obj); 75 console.log(query); 76 /* queryの内容 77 ?grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=ASSERTION&client_id=CLIENT_ID&client_secret=CLIENT_SECRET 78 */ 79 80 81 // axiosライブラリで認証用URLとクエリ文字列をPOST 82 let accessToken = await axios.post( 83 authenticationUrl, 84 query 85 ).then(response => response.data.access_token); 86 87 console.log(accessToken); 88 return accessToken; 89 90 /* BOX のコードサンプル 91 return accessToken = await axios.post( 92 authenticationUrl, 93 querystring.stringify({ 94 grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', 95 assertion: assertion, 96 client_id: config.boxAppSettings.clientID, 97 client_secret: config.boxAppSettings.clientSecret 98 }) 99 ) 100 .then(response => response.data.access_token) 101 */ 102}

試したこと

https://support.box.com/hc/ja/articles/360044192233-API-Salesforce-SDK-Invalid-Crypto-Key-%E7%84%A1%E5%8A%B9%E3%81%AA%E6%9A%97%E5%8F%B7%E9%8D%B5-
を参考に、秘密キーをopenSSLで復号化※し、それをKJUR.jws.JWS.signに渡す
※-----BEGIN PRIVATE KEY-----で始まるもの

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答1

0

自己解決

スクリーニングの組合せが多く、大変でした・・・。

Javascript

1const getBoxAccessToken = async () => { 2 3 // 読取専用のレコードからコンフィグ情報(JSON)を読み取る 4 let config = await getBoxConfig(); 5 BoxConfig = JSON.parse(config.Response.Data[0].Body); 6 7 if (!config) { 8 alert('BOX API コンフィグ情報の取得に失敗しました'); 9 return; 10 } 11 12 // 秘密キーをパスコードを使って復号化 13 let prvKey = ''; 14 prvKey = KEYUTIL.getKey(BoxConfig.boxAppSettings.appAuth.privateKey); 15 16 // 認証用URLの定数宣言 17 const authenticationUrl = "https://api.box.com/oauth2/token"; 18 19 // ペイロードを宣言 20 let oPayload = {}; 21 oPayload.iss = BoxConfig.boxAppSettings.clientID; 22 oPayload.sub = BoxConfig.enterpriseID; 23 oPayload.box_sub_type = 'enterprise'; 24 oPayload.aud = authenticationUrl; 25 oPayload.jti = KJUR.crypto.Util.getRandomHexOfNbytes(64); 26 oPayload.exp = Math.floor(Date.now() / 1000) + 45; 27 28 let sPayload = JSON.stringify(oPayload); 29 30 // 公開キーIDを格納 31 let keyId = BoxConfig.boxAppSettings.appAuth.publicKeyID; 32 33 // ヘッダーを宣言 34 let oHeader = { 35 alg: 'RS256', 36 cty: 'JWT', 37 keyid: keyId 38 } 39 40 let sHeader = JSON.stringify(oHeader); 41 42 // ヘッダー、ペイロードをキー情報を使って署名 43 // prvKey 使用 44 let assertion = KJUR.jws.JWS.sign(null, sHeader, sPayload, prvKey); 45 46 let grantType = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&'; 47 // クエリ文字列作成用のオブジェクト宣言 48 let obj = { 49 assertion: assertion, 50 client_id: BoxConfig.boxAppSettings.clientID, 51 client_secret: BoxConfig.boxAppSettings.clientSecret 52 } 53 54 // クエリ文字列変換ライブラリを使用してクエリ文字列を生成 55 let query = grantType + serialize(obj).slice(1); 56 57 // axiosライブラリで認証用URLとクエリ文字列をPOST 58 let accessToken; 59 return accessToken = await axios.post( 60 authenticationUrl, 61 query 62 ).then(response => response.data.access_token) 63}

投稿2021/12/12 05:56

Xi-wang

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問