2025年12月23日火曜日

Role based JWT profileで保護したORDS REST APIにアクセスする - Microsoft Entra ID編

更新:2026年2月27日

ORDS RESTサービスとして作成したリモートMCPサーバーをMicrosoft Entra IDで認証します。

以下の記事にそって構築した環境を使用します。
この手順に含まれる構成スクリプトによって、以下の記事で説明しているWWW-_Authenticateヘッダーを書き換える設定も実装されています。
動作確認にMCP Inspector、Claude Desktop、OpenAI ChatGPTを使用します。

Microsoft Entra IDでのアプリ登録手順は、おおむね以下の記事と同じです。

SQLclのMCPサーバーのデータベース接続をMicrosoft Entra IDのOAuth2で認証する

SQLclのMCPサーバーのデータベース接続にTOKEN_AUTH=AZURE_INTERACTIVEの設定を使用する
https://apexugj.blogspot.com/2025/08/sqlcl-mcp-with-azure-interactive.html


Microsoft Entra IDの設定



接続先となるORDS RESTサービスに対応するアプリケーションを作成します。

Microsoft Azureのコンソールより、Microsoft Entra IDを開きます。

規定のディレクトリよりアプリの登録を開き、新規作成を実行します。


名前ORDS MCPとします。リダイレクトURI省略します。リダイレクトURIはクライアントに対応するアプリケーションに作成します。

アプリケーションを登録します。


管理APIの公開を開き、Scopeの追加を実施します。

リモートMCPサーバーをMicrosoft Entra IDで認証する場合、リソース・サーバーは401 Unauthorizedのレスポンスを返すときにWWW-Authenticateヘッダーで、ここで作成するスコープを返す必要があります。


アプリケーションIDのURIとして、デフォルト値を設定します。

保存してから続けるをクリックします。


作成するスコープのスコープ名mcp:connectとします。同意できるのはだれですか?として管理者とユーザーを選択します。管理者の同意の表示名管理者の同意の説明ともに「Connect to My MCP Server」と記述します。

状態有効を選択し、スコープの追加をクリックします。


管理アプリロールを開き、アプリロールの作成をクリックします。

ロールによってORDS RESTモジュールを保護するので、ここで作成するアプリロールと同名のロールを、ORDSに作成します。


表示名ORDS REST APIの呼び出し許可されたメンバーの種類両方(ユーザー/グループ+アプリケーション)を選択します。

ORDSUsers(これがORDSのロール名になります)、説明は「ORDS REST APIの呼び出し」と記述します。

このアプリロールを有効にしますか?チェックし、適用をクリックします。


アプリケーションORDS MCPをEntra IDのユーザーに割り当てます。割り当てるユーザーに、作成したアプリロールORDSUsersを割り当てます。

ユーザーの割り当ては、エンタープライズアプリケーションに移動して実施します。

概要から、ローカルディレクトリのマネージドアプリケーションのリンクを開きます。


管理ユーザーとグループを開き、ユーザーまたはグループの追加Add user/group)をクリックします。


ユーザー選択されていませんをクリックし、ユーザーを割り当てます。


先ほど作成したアプリロールORDSUsersを割り当てるユーザーを選択し、選択をクリックします。


割り当てるロール「ORDS REST APIの呼び出し」(値はORDSUsers)は、すでに選択されています。

割り当てをクリックします。


以上でユーザーにアプリロールORDSUsersが割り当てられました。

規定のディレクトリに戻り、アプリの登録を開きます。すべてのアプリケーションから、先ほど作成したORDS MCPを開きます。


APIのアクセス許可を開き、アクセス許可の追加をクリックします。


所属する組織で使用しているAPIを開き、ORDS MCPを探して選択します。


アプリケーションの許可を選択します。

アクセス許可としてアプリロールORDSUsersが表示されます。このORDSUsersチェックして、アクセス許可の追加を実行します。


アクセス許可にORDSUsersが追加されました。

アクセス許可の追加を再度クリックします。


先ほどと同様に、所属する組織で使用しているAPIを開き、ORDS MCPを探して選択します。

今度は認可されたアクセス許可を選択し、アクセス許可として表示されたmcp:connectチェックして、アクセス許可の追加を実行します。


以上でアクセス許可の設定ができました。

Entra IDのアクセストークンをv2に変更します。

マニュフェストを開きます。


Microsoft Graphアプリマニュフェストの"api"の下にある、requestedAccessTokenVersionをnullからへ変更します。

変更後、保存します。


Entra ID v2アクセストークンでは、ユーザーの識別子となるclaimとしてupnを使用します。

トークン構成を開き、オプションの要求の追加をクリックします。


トークンの種類アクセスを選択し、要求に含まれるupnチェックします。これはOAuth2のアクセストークンに、claimとしてupnを追加するという作業です。

以上で追加をクリックします。


Microsoft Graph profileのアクセス許可を有効にしますチェックして、追加します。


必ずしも必要ではないようですが、念の為同様の操作を行い、IDトークンについてもclaimとしてupn追加します。


以上でIDトークンとアクセストークンの両方に、属性としてupnが含まれるようになりました。

属性upnに設定される値を調整します。要求upnの3点メニューをクリックし、編集を実行します。


UPNの編集画面で、外部認証済みはいハッシュ記号の置換はいに設定します。

以上で保存します。


同じ作業をIDトークンとアクセストークンの両方で実施します。


以上で一旦、サーバーに対応したアプリケーションの設定は完了です。


次にクライアントに対応したアプリケーションを作成します。

規定のディレクトリ管理アプリの登録を開き、新規登録を実行します。


作成するアプリケーションの名前ORDS MCP Clientとします。リダイレクトURIとして、MCP Inspector、ブラウザ版ChatGPTおよびClaude DesktopのURIの3つを設定する必要があるため、ここでの設定は省略します。

以上で登録します。


アプリケーションORDS MCP Clientが作成されます。

後ほどサーバー側のアプリケーションORDS MCPへの紐付けに使うため、アプリケーション(クライアント)IDコピーしておきます。その後に、リダイレクトURIを追加するのリンクを開きます。


リダイレクトURIを構成します。

リダイレクトURIの追加
をクリックし、最初にMCP InspectorのリダイレクトURIを追加します。


MCP InspectorのリダイレクトURIは、MCP InspectorのTransport TypeとしてStreamable HTTPを選択したときに、Authenticationの中に表示されるOAuth 2.0 FlowRedirect URLの値です。macOSで実行したMCP Inspectorでは以下のURLでした。

http://localhost:6274/oauth/callback


MCP Inspectorでは、プラットフォームにシングルページアプリケーションを選択します。


MCP InspectorリダイレクトURIを設定し、構成を実行します。


続いて、ブラウザ版ChatGPTとClaude DesktopのリダイレクトURIを構成します。

ChatGPTとClaude Desktopでは、プラットフォームにWebを選択します。MCP InspectorはSPAなので、ブラウザ版ChatGPTやClaude DesktopもSPAとして扱うと勝手に考えていましたが、ChatGPTに相談したところ、リダイレクトURIがhttps://chatgpt.comやhttps://claude.aiならWebです、とChatGPTに指摘されました。

OktaやAuth0、Oracle IAMはSPAとして設定できるので、Entra IDではWebである理由は不明です。Entra IDでの認証時にはクライアントIDに加えてクライアント・シークレットの指定も必要なので、DCRとPKCEが、ChatGPTやClaude Desktopが期待しているようには動作しないのかもしれません。


リダイレクトURIにChatGPTのリダイレクトURIを設定し、構成を実行します。

https://chatgpt.com/connector_platform_oauth_redirect


2026年3月4日追記 - OpenAI ChatGPTのコールバックURLは仕様が変更された模様で、登録するアプリごとに異なるURLが発行されるようです。リダイレクトURIにワイルドカードが使用できない場合、表示されたコールバックURLをリダイレクトURLとして設定する必要があります。


同様にClaude DesktopのリダイレクトURI構成します。

https://claude.ai/api/mcp/auth_callback


設定を開き、パブリッククライアントフローを許可します。

パブリッククライアントフローを許可するとPKCEが実行されるため、クライアント・シークレットの指定は不要になるはずですが、Claude DesktopとChatGPTはそうなっていません。MCP Inspectorに限り、クライアント・シークレットの指定が不要でした。


パブリッククライアントフローを許可する有効にし、保存します。


シークレットが必要なクライアント向けに、証明書とシークレットを開き、新しいクライアントシークレットを作成します。


説明secretと記述し、有効期限はデフォルトの推奨: 180 日(6ヶ月)を選択し、クライアントシークレットを追加します。


追加されたシークレットの値(シークレットIDではない)をコピーし、保存しておきます。ChatGPTのアプリやClaude Desktopのカスタムコネクタを作成する際に使用します。


アプリの登録に戻り、アプリケーションORDS MCPを開きます。


APIの公開を開き、クライアントアプリケーションの追加を実行します。


クライアントIDにクライアントに対応するアプリケーションORDS MCP Clientアプリケーション(クライアント)IDを設定します。承認済みのスコープはサーバーであるアプリケーションORDS MCPアプリケーション(クライアント)IDを含むので、スコープに含まれるIDとは異なるIDになります。

承認済みのスコープをチェックし、アプリケーションの追加を実行します。


承認済みのクライアント・アプリケーションとしてORDS MCP Clientが追加されます。


以上でEntra IDの設定は完了です。


ORDSおよびnginxの設定


作成したAPEXワークスペースに開発者ユーザーでサインインし、SQLワークショップのSQLコマンドを開きます。または、APEXワークスペースのデフォルト・パーシング・スキーマにSQLclで接続します。

以下のスクリプトを実行し、Oracle REST Data Servicesに権限oracle.example.mcpを作成(すでに存在する場合は再定義)します。ロールとしてORDSUsersを作成し、RESTモジュールsampleserverを保護します。
declare
    l_roles    owa.vc_arr;
    l_modules  owa.vc_arr;
    l_patterns owa.vc_arr;
begin
    ords.create_role(
        p_role_name => 'ORDSUsers'
    );
    l_modules(1) := 'sampleserver';
    l_roles(1)   := 'ORDSUsers';
    ords.define_privilege(
        p_privilege_name => 'oracle.example.mcp',
        p_label          => 'Priviledge for MCP',
        p_roles          => l_roles,
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/

issuerがわからないため、ORDS_SECURITY.CREATE_JWT_PROFILEの実行より先に、/.well-known/以下を設定します。

リバース・プロキシ(OpenRestyまたはnginx)を実行しているコンピュート・インスタンスに接続します。

rootユーザーで作業します。

sudo -s

[opc@ordsmcp ~]$ sudo -s

[root@ordsmcp opc]# 


nginxのドキュメント・ルートに移動します。

cd /usr/share/nginx/html

[root@ordsmcp opc]# cd /usr/share/nginx/html

[root@ordsmcp html]# 


ディレクトリ.well-knownを作成します。

mkdir .well-known

[root@ordsmcp html]# mkdir .well-known

[root@ordsmcp html]# 


以下を記述したファイルを、.well-known/oauth-protected-resourceとして作成します。
{
  "resource": "アプリケーションORDS MCPのアプリケーション(クライアント)ID",
  "authorization_servers": [ 
    "https://login.microsoftonline.com/テナントID/v2.0"
  ],
  "scopes_supported": ["api://アプリケーションORDS MCPのアプリケーション(クライアント)ID/mcp:connect"]
}
resourceの値は、サーバーに対応したアプリケーションORDS MCP概要にあるアプリケーション(クライアント)IDです。


authorization_serversはJSON配列で、要素となる値は概要エンドポイントにあるOpenID Connectメタデータドキュメントの末尾の/.well-known/openid-configurationを除いた部分です。


scopes_supportedはJSON配列で、要素となる値はAPIの公開にあるスコープです。


authorization_serversが認識されない場合を想定し、認可サーバーのメタデータをリソース・サーバーに配置します。

OpenID Connectメタデータドキュメントをダウンロードし、.well-known以下にoauth-authorization-serverとして配置します。

curl -L -o .well-known/oauth-authorization-server https://login.microsoftonline.com/********-****-****-****-************/v2.0/.well-known/openid-configuration

[root@ordsmcp html]# curl -L -o .well-known/oauth-authorization-server https://login.microsoftonline.com/3940****-****-****-****-********2758/v2.0/.well-known/openid-configuration

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  1965  100  1965    0     0   3470      0 --:--:-- --:--:-- --:--:--  3471

[root@ordsmcp html]#


/etc/nginx/nginx.conf
(または/usr/local/openresty/nginx/conf/nginx.conf)を開き、ヘッダー情報がログに出力されるextended.logが有効になるように、access_logのコメントを変更します。

    #access_log  /var/log/nginx/access.log  main;

    access_log   /var/log/nginx/extended.log extended;

    #access_log   /var/log/nginx/body.log body;


/etc/nginx/default.d/40-www-auth.confを開き、WWW-Authenticateヘッダーがスコープを返すように変更します。scope=で指定する値は、/.well-known/oauth-protected-resourceのscopes_supportedに含まれている値です。

location @ords_401 {

    internal;

    more_clear_headers 'WWW-Authenticate';

    # The same IdP is used for all MCP servers.

    #add_header WWW-Authenticate 'Bearer resource_metadata="$scheme://$host/.well-known/oauth-protected-resource"' always;

    # scope for Microsoft Entra ID

    add_header WWW-Authenticate 'Bearer resource_metadata="$scheme://$host/.well-known/oauth-protected-resource",scope="api://e375****-****-****-****-********6872/mcp:connect"' always;

    # “A dedicated IdP is assigned to each MCP server.

    #add_header WWW-Authenticate 'Bearer resource_metadata="$scheme://$host/.well-known/oauth-protected-resource$uri"' always;


以上の変更を実施し、nginxをリロードします。

nginx -s reload
または
/usr/local/openresty/nginx/sbin/nginx -s reload

[root@ordsmcp html]# nginx -s reload

[root@ordsmcp html]# 


extended.logの出力を監視します。

tail -f /var/log/nginx/extended.log

[root@ordsmcp html]# tail -f /var/log/nginx/extended.log



MCP Inspectorを起動し、リモートMCPサーバーに接続します。

npx @modelcontextprotocol/inspector


Entra IDへのサインインが要求されます。アプリロールORDSUsersを割り当てたユーザーでサインインします。


Entra IDへのサインインが成功しても、ORDSのJWTプロファイルが設定されていない、つまりRESTサービスの呼び出しが許可されないため、MCPサーバーへの接続は失敗します。

サインインは成功しているため、extended.logにアクセストークンが出力されます。

接続を諦めるまでサインインが繰り返されるので、アクセストークンが確認できたらMCP InspectorをCTRL+Cで停止するとよいでしょう。


アクセストークンをコピーし、https://jwt.ioなどを使って内容をデコードします。


アクセストークンに含まれる属性audおよび属性issの値をコピーします。また、rolesクレームが存在し、JSON配列の要素としてアプリロールORDSUsersが含まれていることを確認します。

属性audはORDS_SECURITY.CREATE_JWT_PROFILEの引数p_audienceの値になります。属性issは引数p_issuerの値になります。

ブラウザでOpenID ConnectメタデータのURLを開き、属性jwks_uriの値をコピーします。この値は、ORDS_SECURITY.CREATE_JWT_PROFILEの引数p_jwk_urlの値になります。


これらの値を引数に与えて、ORDS_SECURITY.CREATE_JWT_PROFILEを呼び出し、JWTプロファイルを作成します。引数p_role_claim_nameには/rolesを与えます。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => '属性issの値'
        ,p_audience => '属性audの値'
        ,p_jwk_url => '属性jwks_uriの値'
        ,p_role_claim_name => '/roles'
    );
end;
/

ビューUSER_ORDS_JWT_PROFILEを検索し、設定内容を確認します。

select issuer,audience,jwk_url,role_claim_name from user_ords_jwt_profile


以上で、ORDS RESTサービスの保護も完了です。

再度MCP Inspectorから接続します。

今度はConnectedになります。



クライアントからの接続確認



ブラウザ版ChatGPTより接続してみます。

設定のアプリを開き、高度な設定のアプリを作成するを実行します。(ChatGPTが開発者モードである必要があります。)


新しいアプリの名前My Oracle Appとします。MCPサーバーのURLとして、ORDS REST APIのエンドポイントURLを設定します。

認証OAuthを選択し、クライアントに対応したアプリケーションORDS MCP Clientアプリケーション(クライアント)IDクライアント・シークレットを指定します。

理解した上で、続行しますチェックし、作成するをクリックします。


以下のように接続に成功し、リモートMCPサーバーのツールがアクションとして表示されます。
 


ChatGPTで新しいチャットを開始し、作成したアプリMy Oracle Appのツールget_schemaを呼び出します。

My Oracle Appのget_schemaを呼び出して。


リモートMCPサーバーのツール呼び出しもできました。

Claude Desktopでも、ChatGPTと同じ設定で、リモートMCPサーバーをカスタムコネクタを追加します。

設定コネクタを開きます。カスタムコネクタを追加します。


カスタムコネクタの名前My Oracle Appとします。リモートMCPサーバーURLとして、ORDS REST APIのエンドポイントURLを設定します。

詳細設定OAuth Client IDORDS MCP Clientアプリケーション(クライアント)IDOAuthクライアントシークレットクライアント・シークレットを指定します。

以上を設定し、追加をクリックします。


新しいClaude Desktopではコネクターがカスタマイズに移動したとのことです。

カスタマイズを開きます。


コネクタMy Oracle Appを選択し、連携/連携させるを実行します。


ブラウザが起動し、Entra IDでのサインインが要求されます。


Entra IDでのサインインが完了すると、コネクタとして利用できるツールが確認できます。


ChatGPTと同様に、チャットから呼び出してみます。

My Oracle Appのget_schemaを呼び出して。


Claude Desktopでも、ORDS REST APIをEntra IDで認証してアクセスできました。

今回の記事は以上です。