このドキュメントでは、JSON Web Token (JWT) を使用するカスタムアプリケーションが、Drive and Photo Service (PDS) にアクセスするためのアクセストークンを取得する方法について説明します。
JWT アプリケーション
JWT アプリケーションとは、カスタムアプリケーション の一種で、ID 認証 に JSON Web Token (JWT) メカニズムを使用するものです。
JWT アプリケーションのサーバーは、秘密鍵でデータに署名して JWT アサーションを生成できます。この文字列は、対応する公開鍵が設定された PDS サーバーにアクセスするための認証情報として機能します。

ユースケース
-
組織に独自のアカウントシステムを持つ内部ソフトウェアシステムがあり、ユーザーが内部のログインページからサインインしてから PDS の機能を使用できるようにしたい場合。
-
組織に独立したアカウントシステムとログインポータルがあり、既存のログインポータルと PDS を組み合わせて、既存のアカウントを使用するクラウドストレージシステムを構築したい場合。
ワークフローの概要
-
PDS コンソールで、カスタムドメインと JWT アプリケーションを作成します。
-
RSA アルゴリズムを使用して公開鍵と秘密鍵のキーペアを生成します。公開鍵を PDS サーバーに保存し、秘密鍵を JWT アプリケーションサーバーに保存します。
-
JWT アプリケーションサーバーがデータをエンコードし、秘密鍵で署名して JWT アサーションを生成し、PDS サーバーに送信します。
-
PDS サーバーは公開鍵を使用して JWT アサーションを検証します。検証に成功すると、アクセストークンが JWT アプリケーションサーバーに返されます。その後、サーバーはアクセストークンを使用して PDS API を呼び出すことができます。
手順
ステップ 1:キーの設定
1.1 ドメインの作成または選択
Drive and Photo Service (PDS) コンソールの [Domain List] ページで、[Create Domain] をクリックします。表示されたパネルで、[Domain Name] (例:「Drive Demo」) と [Description] を入力し、[Data Storage Mode] を [Standard Mode] に設定し、[Enable Initial Drive] スイッチをオンにし、[Custom Size] を選択して Drive のサイズ (例: 10 GB) を設定してから、[OK] をクリックします。
1.2 アプリケーションの作成または選択
ドメイン詳細ページに移動し、[Applications] タブでアプリケーションを作成または選択します。
[Create Application] ダイアログボックスで、[Application Access Method] に [Access as Application] を選択します。[Type] には [Access with JWT Authentication] を選択します。[Application Name] (例: Demo Drive) を入力します。[Permission Scope] には [Custom] を選択し、DRIVE.ALL、SHARE.ALL、FILE.ALL、USER.ALL、STORAGE.ALL、STORAGEFILE.LIST、ACCOUNT.ALL、BATCH の権限を選択します。[OK] をクリックします。
1.3 公開鍵の設定
アプリケーションを作成または選択した後、その公開鍵を設定する必要があります。
ドメイン詳細ページで、[Applications] タブを選択します。[My Applications] セクションで、対象のアプリケーションを見つけ、[操作] 列の [Set Public Key] をクリックします。
表示されたダイアログボックスで、[No key pair? Click here to generate one] リンクをクリックして新しいキーペアを生成します。生成された公開鍵を [Public Key PEM] テキストボックスに貼り付けます。
キーペアを生成した後、秘密鍵をコピーして安全な場所に保存します。その後、[OK] をクリックします。
公開鍵の変更は 5 分以内に有効になります。
ステップ 2:アクセストークンの取得
2.1 JWT アサーションの構築と署名
アプリケーションサーバー上で、ペイロードデータをエンコードし、指定された暗号化アルゴリズムを使用して秘密鍵で署名し、JWT アサーションを生成します。以下の Node.js コードは一例です。
const JWT = require('jsonwebtoken');
function signAssertion({ domain_id, client_id, user_id, privateKeyPEM }) {
var now_sec = parseInt(Date.now() / 1000);
var opt = {
iss: client_id,
sub: user_id,
sub_type: "user",
aud: domain_id,
jti: Math.random().toString(36).substring(2),
exp: now_sec + 300,
// iat: now_sec, // 発行時刻 (現在の UNIX タイムスタンプ、秒単位)
// nbf: '', // 有効期間の開始時刻 (UNIX タイムスタンプ、秒単位)
auto_create: false,
};
return JWT.sign(opt, privateKeyPEM, {
algorithm: "RS256",
});
}
JWT ペイロードのクレーム
|
パラメーター |
必須 |
タイプ |
説明 |
|
iss |
はい |
String |
アプリ ID。 |
|
sub |
はい |
String |
ユーザー ID またはドメイン ID。 |
|
sub_type (拡張フィールド) |
はい |
String |
アカウントタイプ。有効値: |
|
aud |
はい |
String |
ドメイン ID。 |
|
jti |
はい |
String |
アプリケーションによって生成される JWT の一意の識別子。長さは 16~128 文字である必要があります。UUID の使用を推奨します。 |
|
exp |
はい |
Integer |
JWT の有効期限。秒単位の UNIX タイムスタンプで表します。 |
|
iat |
いいえ |
Integer |
発行時刻。秒単位の UNIX タイムスタンプで表します。例: |
|
nbf |
いいえ |
Integer |
「not before」時刻。秒単位の UNIX タイムスタンプで表します。指定しない場合、デフォルトで現在時刻になります。 |
|
auto_create (拡張フィールド) |
いいえ |
Boolean |
ユーザーが存在しない場合に自動的に作成するかどうかを指定します。デフォルト: |
JWT ライブラリと署名方法の詳細については、「JWT 公式ウェブサイト」をご参照ください。
2.2 アクセストークンの取得
Authorize API を呼び出して、JWT アサーションを access_token と交換します。
POST /v2/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=${APP_ID}&assertion=xxxxxxxxxx
リクエストの Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。リクエストパラメーターはリクエストボディに配置します。
リクエストパラメーター
|
パラメーター |
必須 |
タイプ |
説明 |
|
grant_type |
はい |
String |
グラントタイプ。文字列定数 |
|
client_id |
はい |
String |
アプリ ID。 |
|
assertion |
はい |
String |
前のステップで生成された JWT アサーション。 |
レスポンスの例
{
"access_token": "eyJh****eQdnUTsEk4",
"refresh_token": "kL***Lt",
"expires_in": 7200,
"token_type": "Bearer"
}
アプリケーションサーバーが access_token を受信した後、そのトークンをクライアント側のアプリケーションに返すことができます。その後、アプリケーションは API コールに access_token を含めることで、PDS 内のユーザーリソースにアクセスできます。
2.3 アクセストークンの更新
JWT フローで取得した access_token は 2 時間有効です。有効期限が切れた後、refresh_token を使用して新しい access_token を取得できます。refresh_token の有効期間は 7 日間です。有効期限が切れた後は、ステップ 2.1 と 2.2 を繰り返して、完全に新しいトークンを生成する必要があります。または、いつでもステップ 2.1 と 2.2 を繰り返して新しい access_token を取得することもできます。
Authorize API を呼び出して、refresh_token を新しい access_token と交換します。
POST /v2/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=${APP_ID}&refresh_token=${refresh_token}&grant_type=refresh_token&redirect_uri=${REDIRECT_URI}
|
パラメーター |
必須 |
タイプ |
説明 |
|
client_id |
はい |
String |
アプリ ID。 |
|
refresh_token |
はい |
String |
前のトークンレスポンスからの |
|
grant_type |
はい |
String |
グラントタイプ。文字列定数 |
|
redirect_uri |
はい |
String |
アプリケーション作成時に指定したコールバック URL。 |
ステップ 3:Basic UI の使用 (任意)
独自の UI を開発せず、公式の Basic UI が要件を満たしている場合は、直接使用できます。
方法 1:新しいウィンドウで開く
window.open を使用して Basic UI を開き、postMessage を使用してアクセストークンを渡します。
コード例:
const endpoint = `https://${domain_id}.apps.aliyunpds.com`
const url = `${endpoint}/accesstoken?origin=${location.origin}`
var win = window.open(url)
window.addEventListener('message', onMessage, false)
async function onMessage(e) {
if (e.data.code == 'token' && e.data.message == 'ready') {
var result = await getToken(); // サーバーからアクセストークンを取得します。
// result = {"access_token": ...}
win.postMessage({
code: 'token',
message: result
}, endpoint || '*')
window.removeEventListener('message', onMessage)
}
}
方法 2:カスタムログインページへの埋め込み
iframe を使用して、Basic UI をカスタムログインページに埋め込みます。
Basic UI がトークンを自動的に更新できるようにするには、システム設定でカスタムログインページの URL と JWT アプリケーションのアプリ ID を設定します。
[Enterprise Settings] > [Advanced Customization] ページに移動します。[Custom Login and Logout] セクションで設定を完了します。[Custom Logout Page URL] を設定することもできます。設定後、ログアウトすると自動的にカスタムログアウトページにリダイレクトされ、ログイン状態がクリアされます。
ユーザーがログインすると、Basic UI のデフォルトのログインページの代わりに、カスタムログインページが iframe 内で開かれます。
ログインに成功した後、postMessage を使用してトークンをホストページに渡します。

if(parent!=self){
let origin = ''
parent.postMessage({
code: 'token',
message: {
access_token: 'xxxx',
refresh_token: 'xxxx',
...
}
}, endpoint || "*")
}
付録 1:Node.js コード実装
以下のサンプルコードは、JWT アプリケーションが access_token を取得および更新する方法を示しています。
const fs = require('fs')
const JWT = require('jsonwebtoken');
const axios = require('axios')
const DOMAIN_ID = '' // ご自身の domain ID
const APP_ID = '' // ご自身の application ID
const USER_ID = '' // ユーザー ID
const PRIVATE_KEY_PEM = '' // ステップ 1.3 で設定した秘密鍵
const REDIRECT_URI = '' // ご自身のコールバック URL
const PRE = `https://${DOMAIN_ID}.api.aliyunpds.com`
async function init() {
try {
// 以下の変数を実際の値に置き換えてください。
var params = {
domain_id: DOMAIN_ID,
client_id: APP_ID,
user_id: USER_ID,
privateKeyPEM: PRIVATE_KEY_PEM,
};
var assertion = signAssertion(params)
var obj = await getToken(assertion)
return obj.data
} catch (e) {
if (e.response) {
console.log(e.response.status)
console.log(e.response.headers)
console.log(e.response.data)
} else {
console.error(e)
}
}
}
function signAssertion({ domain_id, client_id, user_id, privateKeyPEM }) {
var now_sec = parseInt(Date.now()/1000)
var opt = {
iss: client_id,
sub: user_id,
sub_type: 'user',
aud: domain_id,
jti: Math.random().toString(36).substring(2),
exp: now_sec + 300,
// iat: now_sec,
// nbf: '',
auto_create: true,
};
return JWT.sign(opt, privateKeyPEM, {
algorithm: 'RS256'
});
}
async function getToken(assertion) {
return await axios({
method: 'post',
url: PRE + '/v2/oauth/token',
// 注:Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
// 注:リクエストパラメーターはリクエストボディに配置します。
data: params({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
client_id: APP_ID,
assertion
})
})
}
async function refreshToken(refresh_token) {
return await axios({
method: 'post',
url: PRE + '/v2/oauth/token',
// 注:Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
// 注:リクエストパラメーターはリクエストボディに配置します。
data: params({
grant_type: 'refresh_token',
client_id: APP_ID,
refresh_token,
redirect_uri: REDIRECT_URI,
})
})
}
function params(m){
const params = new URLSearchParams();
for(var k in m){
params.append(k, m[k]);
}
return params;
}
// 関数のテスト
;(async ()=>{
let result = await init()
console.log(result) // トークンオブジェクト {access_token:...} を返します。オブジェクトの構造については、付録 2 をご参照ください。
// access_token の有効期限が切れた後
refreshToken(result.refresh_token) // 新しいトークンオブジェクト {access_token:...} を返します。オブジェクトの構造については、付録 2 をご参照ください。
})();
付録 2:トークンオブジェクトの構造
レスポンスの例:
{
"access_token": "eyJhbG.....g7M0p28",
"refresh_token": "62f1acc.......9b781f3",
"expires_in": 7200,
"token_type": "Bearer",
"..." : "..."
}
パラメーターの詳細については、「アクセストークンの取得」をご参照ください。