アプリケーション識別および許可
IBM Cloud® App ID を導入すると、OAuth2.0 機能を利用したアプリケーション識別および許可フローを使用して、アプリケーションを保護することができます。
通信フローについて
さまざまな場面で、あるアプリケーションがユーザー介入なしで別のサービスまたはアプリと通信できると便利です。 例えば、非対話式アプリが作業を実行するために、別のアプリケーションへのアクセスが必要になる場合があります。 これが必要になる発信元としては、プロセス、CLI、デーモンなどが含まれます。また、モニターを行ってアップストリーム・サーバーに環境変数を報告する IoT デバイスも含まれます。 具体的なユース・ケースはアプリケーションごとに異なりますが、留意すべき最も重要な点は、要求がエンド・ユーザーではなくアプリのために交換されること、また認証と許可の対象がアプリであることです。
フローの仕組み
App ID は、OAuth 2.0 クライアント資格情報フローを利用して通信を保護します。 アプリが App ID に登録されると、そのアプリはクライアント ID とシークレットを取得します。 アプリは、これらの情報を使用して App ID にアクセス・トークンを要求し、保護リソースまたは保護 API へのアクセスが許可されます。 アプリケーション識別および許可フローでは、アプリケーションに与えられるのはアクセス・トークンのみです。 識別トークンやリフレッシュ・トークンは取得しません。 トークンについて詳しくは、トークンについてを参照してください。
このワークフローは、秘密が悪用されたり漏洩したりする危険性がない、信頼できるアプリケーションでのみ使用されることを意図している。 アプリケーションは常にクライアント・シークレットを保持します。 モバイル・アプリには向いていません。
フローの概要
以下のイメージは、サービスとアプリケーションの間の通信の方向を示しています。
- 保護リソースにアクセスするために認証を受ける必要があるアプリケーションを App ID に登録します。
- アプリケーション A は、App ID に登録され、クライアント ID とシークレットを取得します。
- アプリケーション A は、前のステップで取得した資格情報を送信して、App ID 許可サーバーの
/token
エンドポイントに要求を行います。 - App ID は要求を検証し、アプリを認証し、アクセス・トークンを入れた応答をアプリケーション A に返します。
- アプリケーション A は、その有効なアクセス・トークンを使用して、アプリケーション B などの保護リソースに要求を送信できるようになりました。
クライアントの認証に使用するクライアント・シークレットは、機密性が非常に高いので機密を維持する必要があります。 アプリケーションはアプリ内でクライアントシークレットを使用するため、このワークフローは信頼できるアプリケーションでのみ使用しなければならない。 信頼できるアプリケーションを使用することで、クライアント・シークレットの漏えいや悪用を防止します。
アプリの登録
GUI を使用する場合
- App ID ダッシュボードの**「アプリケーション」タブで、「アプリケーションの追加」**をクリックします。
- アプリケーション名を追加し、**「保存」**をクリックして、登録済みアプリのリストに戻ります。 アプリケーションの名前は 50 文字を超えてはなりません。
- 登録済みアプリのリストから、前のステップで追加したアプリケーションを選択します。 行が展開され、資格情報が表示されます。
API を使用する場合
-
/management/v4/<tenantID>/applications
エンドポイントに対して POST 要求を行います。curl -X POST \ https://<region>.appid.cloud.ibm.com/management/v4/<tenantID>/applications/ \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <IAMToken>' \ -d '{"name": "<applicationName>"}'
応答の例:
{ "clientId": "c90830bf-11b0-4b44-bffe-9773f8703bad", "tenantId": "b42f7429-fc24-48fa-b4f9-616bcc31cfd5", "secret": "YWQyNjdkZjMtMGRhZC00ZWRkLThiOTQtN2E3ODEyZjhkOWQz", "name": "testing", "oAuthServerUrl": "https://us-south.appid.cloud.ibm.com/oauth/v4/b42f7429-fc24-48fa-b4f9-616bcb31cfd5", "profilesUrl": "https://us-south.appid.cloud.ibm.com", "discoveryEndpoint": "https://us-south.appid.cloud.ibm.com/oauth/v4/b42f7429-fc24-48fa-b4f9-616bcb31cfd5/.well-known/openid-configuration" }
アクセス・トークンの取得
アプリが App ID に登録され、資格情報を取得したら、App ID 許可サーバーに要求を行ってアクセス・トークンを取得することができます。
-
/token
エンドポイントに HTTP POST リクエストを行う。 要求の許可はBasic auth
であり、クライアント ID とシークレットを Base64 でエンコードしたユーザー名およびパスワードとして使用します。curl -X POST https://<region>.appid.cloud.ibm.com/oauth/v4/<tenantID>/token \ -H 'Authorization: Basic base64Encoded{clientId:secret}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials'
応答の例:
{ "access_token": "eyJhbGciOiJS...F9A", "expires_in": "3600", "token_type": "Bearer" }
チュートリアル: Node.js SDK を使用したエンドツーエンドのフロー
-
以下のいずれかの方法でアクセス・トークンを取得します。
-
App ID Node.js サーバー SDK から、トークン マネージャーを使用します。 アプリの資格情報を使用してトークン・マネージャーを初期化し、
getApplicationIdentityToken()
メソッドを呼び出してトークンを取得します。const TokenManager = require('ibmcloud-appid').TokenManager; const config = { clientId: "<clientID>", tenantId: "<tenantID>", secret: "{secret}", oauthServerUrl: "https://<region>.appid.cloud.ibm.com/oauth/v4/<tenantID>" }; const tokenManager = new TokenManager(config); tokenManager.getApplicationIdentityToken().then((appIdAuthContext) => { console.log(' Access tokens from SDK : ' + JSON.stringify(appIdAuthContext)); }).catch((err) => { //console.error('Error retrieving tokens : ' + err); });
-
App ID 許可サーバーから取得する。
要求内の
oauthServerUrl
は、アプリケーションの登録時に取得します。 管理 API を使用してアプリを登録した場合、このサーバー URL は応答本文に含まれています。 IBM Cloud コンソールでアプリをバインドして登録した場合、URL は VCAP_SERVICES JSON オブジェクトまたは Kubernetes シークレットで見つけることができます。var request = require('request'); function getAccessToken() { let options = { method: 'POST', url: oauthServerUrl + '/token', headers: { 'content-type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' +Buffer.from('clientId: secret').toString('base64') }, form: { grant_type: 'client_credentials' } }; return new Promise((resolve, reject) => { request(options, function (error, response, body) { if (error) { return reject(error); } let data = JSON.parse(body); if(data.access_token) { resolve(data.access_token); } else { reject(data); } }) }); }
-
-
前のステップで取得したアクセス・トークンを使用して、保護リソースへの要求を行います。
let options = { method: 'GET', url: 'http://localhost:8081/protected_resource', headers: { authorization : 'Bearer ' + accessToken} } request(options, function (error, response, body) { if (error) { console.log(error) } else { res.status(response.statusCode).send({ console.log(JSON.stringify(body)); }); } });
-
App ID Node.js SDK に用意されている API 戦略を使用して、保護リソースをセキュアにします。
const express = require('express'), passport = require('passport'); APIStrategy = require("ibmcloud-appid").APIStrategy; var app = express(); app.use(passport.initialize()); passport.use(new APIStrategy({ oauthServerUrl: "https://{region}.appid.cloud.ibm.com/oauth/v4/{tenant-ID}", tenantId:"{tenant-ID}" })); app.get('/protected_resource', passport.authenticate(APIStrategy.STRATEGY_NAME, {session: false}), (req, res) => { res.send("Hello from protected resource"); });