2024年1月30日火曜日

Microsoft Entra IDのトークンURLを直接呼び出してアクセス・トークンを取得する

Microsoft Entra IDで保護されたリソースの場合、APEX_WEB_SERVICE.MAKE_REST_REQUSTの引数p_token_urlにEntra IDのトークンURLを指定することで、APIの認証を行うことができます。

アクセス・トークンを発行する手順は、Microsoftの次のドキュメント「最初のケース:共有シークレットを使ったアクセス トークン要求」で説明されています。

AzureのAPIをAPEX_WEB_SERVICE.MAKE_REST_REQUSTで呼び出したときに、HTTPステータス・コード 401 Unauthorizedが返されると、APIの認証に関わる値のどれが間違っているのか、APEX_WEB_SERVICE.MAKE_REST_REQUSTのエラーから確認するのは困難です。

そのため、以下のPL/SQLコードでトークンURLを直接呼び出し、アクセス・トークンを取得してみます。

テナントIDアプリケーション(クライアントID)スコープクライアント・シークレットのどれに間違いがあるのか、トークンURLが返すレスポンスから確認できます。

declare
l_token_url varchar2(400);
l_tenant       varchar2(80);
l_response clob;
l_parm_names apex_application_global.vc_arr2;
l_parm_values apex_application_global.vc_arr2;
begin
/*
* Microsoft Entra IDを呼び出してアクセス・トークンを取得する。
* ref https://learn.microsoft.com/ja-jp/azure/active-directory/verifiable-credentials/get-started-request-api
*/
l_tenant       := 'テナントID';
l_token_url := 'https://login.microsoftonline.com/' || l_tenant || '/oauth2/v2.0/token';
l_parm_names(1) := 'client_id';
l_parm_values(1) := 'アプリケーション(クライアント)ID';
l_parm_names(2) := 'scope';
l_parm_values(2) := 'API/アクセス許可のResource App ID'; /* 指定可能なスコープは1つだけ */
l_parm_names(3) := 'client_secret';
l_parm_values(3) := 'クライアント・シークレット';
l_parm_names(4) := 'grant_type';
l_parm_values(4) := 'client_credentials';
apex_web_service.clear_request_headers;
apex_web_service.set_request_headers('Content-Type', 'application/x-www-form-urlencoded', p_reset => false);
l_response := apex_web_service.make_rest_request(
p_url => l_token_url
,p_http_method => 'POST'
,p_parm_name => l_parm_names
,p_parm_value => l_parm_values
);
dbms_output.put_line('status code = ' || apex_web_service.g_status_code);
dbms_output.put_line(l_response);
end;

トークンURLが返してきたレスポンスから、Microsoft Entra IDでアクセス・トークンを要求する場合、scopeに指定できる値(Resource App ID)はひとつだけという制限があり、それに違反していることがわかりました。

認証関連のエラーはデバッグが面倒なので、それを少し助ける方法を紹介しました。

Oracle APEXのアプリケーション作成の参考になれば幸いです。