ラベル Okta の投稿を表示しています。 すべての投稿を表示
ラベル Okta の投稿を表示しています。 すべての投稿を表示

2025年12月17日水曜日

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

更新:2026年2月27日

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

以下の記事にそって構築した環境を使用します。

DNSでホスト名の解決ができ、インターネットからアクセス可能なOracle APEXとORDSの実行環境を作成します。Autonomous AI Databaseを使用する場合は、nginxをリバース・プロキシとして実行する環境だけが必要です。
カスタムのリモートMCPサーバーをORDSのRESTサービスとして実装します。上記で作成したAPEXの環境に、APEXのワークスペースを作成します。
上記で作成したカスタムのリモートMCPサーバーをOAuth2で認証するために、以下の手順にそってnginxのリバース・プロキシに設定を追加します。
確認にMCP Inspector、Claude Desktop、OpenAI ChatGPTを使用します。


Okta Integratorの設定



OktaのAdmin Consoleよりグループを開き、グループを追加します。


グループの名前ORDSUsers説明は「ORDS REST APIへのアクセスを許可」と記述します。

保存をクリックします。


グループに再度アクセスし、グループ一覧を更新します。

作成したグループORDSUsersを開き、ユーザーを割り当てます。


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


グループORDSUsersにユーザーを割り当てます。


ユーザーの割り当てを完了します。


アプリケーション・メニューのアプリケーションを開き、アプリ統合を作成します。


サインイン方法としてOIDC - OpenID Connectを選択します。OIDCを選択するとアプリケーションタイプの選択が現れます。アプリケーションタイプシングルページアプリケーションを選択します。

へ進みます。


アプリ統合を設定します。

アプリ統合名ORDS MCPとします。付与タイプリフレッシュトークンにチェックを入れます。

サインインリダイレクトURIにMCP InspectorのRedirect URLを設定します。ポート番号6274が使用されている場合は、ポート番号が異なるかもしれません。

http://localhost:6274/oauth/callback

サインアウトリダイレクトURIは何を設定すべきか不明なので、x をクリックして削除しておきます。

割り当てアクセス制御として選択されたグループにアクセスを制限を選択し、選択されたグループに先ほど作成したグループORDSUsersを含めます。

以上を設定し保存します。


アプリ統合としてORDS MCPが作成されます。

クライアントIDはMCP InspectorのOAuth 2.0 FlowClient IDに設定する値です。メモしておきます。


MCP Inspectorの以下の場所です。


セキュリティAPIを開き、認証サーバーを追加します。(タブには認可サーバーと書いてあります)


追加する認証サーバーの名前ORDSMCPオーディエンスapi://ordsmcp(本来ordsmcpの部分はGUIDなど、世界で一意になる値を割り当てるのが望ましい)とします。説明としてAuthentication Server for ORDS MCPを入力します。

このオーディエンスの値が、ORDS_SECURITY.CREATE_JWT_PROFILEを呼び出す際の引数p_audienceの値になります。また、oauth-protected-resourceの属性resourceに指定する値になります。

以上で保存します。


追加された認証サーバーの設定タブを開き、メタデータURIを確認します。


このURLで取得できるファイルを、nginxが返す/.well-known/oauth-authorization-serverとして配置します。

URLをブラウザで開き、属性jwks_uriの値をコピーします。

この値はORDS_SECURITY.CREATE_JWT_PROFILEの引数p_jwk_urlの値になります。

また、属性issuerをの値をコピーします。この値はORDS_SECURITY.CREATE_JWT_PROFILEの引数p_issuerの値になります。


メタデータURLの末尾にある.well-known以下を除いた部分が、oauth-protected-resourceauthorization_serversの値になります。

以上でORDS REST APIの保護に必要な値が集まりました。

クレームタブを開き、クレームを追加します。


追加するクレームの名前rolesとします。トークンタイプに含めるアクセス・トークンです。

値タイプグループを選択し、フィルター次で始まるORDSを設定します。このフィルターにより、rolesクレームに先ほど作成したグループORDSUsersが含まれます。

クレームを無効化チェックせず含めるいずれかのスコープを選択します。

以上で作成します。


同様の手順でscopeクレームを追加します。

追加するクレームの名前scopeとします。トークンタイプに含めるアクセストークン値タイプを選択し、として以下を記述します。

String.replace(Arrays.toCsvString(access.scope),","," ")

クレームを無効化チェックせず含めるいずれかのスコープを選択します。

以上で作成します。


rolesクレームとscopeクレームが作成されました。


アクセスポリシーを開き、ポリシーを追加します。


ポリシーの名前ORDS MCPとします。説明に「ORDS MCP」と記述し、次に割り当てる次のクライアントを選択し、クライアントにORDS MCPを含めます。

以上でポリシーを作成します。


アクセスポリシーとしてORDS MCPが作成されました。

ルールを追加します。


ルール名Defaultとします。デフォルトの設定は変更せず(最低限コア付与認証コードチェックされていれば動くはず)、ルールを作成します。


アクセス・ポリシーORDS MCPとルールDefaultが作成されます。


以上でOktaの設定は完了です。


ORDSおよびnginxの設定



ロール・ベースJWTプロファイルを設定します。

ORDS_SECURITY.CREATE_JWT_PROFILEを実行します。それぞれの引数には、今まで集めた設定値を割り当てます。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => 'https://integrator-********.okta.com/oauth2/******************'
        ,p_audience => 'api://ordsmcp'
        ,p_jwk_url => 'https://integrator-********.okta.com/oauth2/******************/v1/keys'
        ,p_role_claim_name => '/roles'
    );
end;
/

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

select issuer,audience,jwk_url,role_claim_name from user_ords_jwt_profile


以下のスクリプトを実行し、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;
/

nginxを実行しているインスタンスに接続し、/.well-known/以下を設定します。

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

sudo -s

[opc@apex ~]$ sudo -s

[root@apex opc]# 


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

cd /usr/share/nginx/html

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

[root@apex html]# 


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

mkdir .well-known

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

[root@apex html]# 


以下を記述したファイルを、.well-known/oauth-protected-resourceとして作成します。resourceには、認可サーバーORDSMCPのオーディエンスの値であるapi://ordsmcpauthorization_serversには、メタデータURIの末尾/.well-known/oauth-authorization-serverを除いたURLを設定します。
{
  "resource": "api://ordsmcp",
  "authorization_servers": {
    "https://integrator-*******.okta.com/oauth2/********************"
  }
}
authorization_serversの設定で、JSON配列ではなく{}で囲んでJSONオブジェクトにしています。構文的に間違っていますが、authorization_serversが認識できないと、認可サーバーの代わりにリソース・サーバー上の/.well-known/oauth-authorization-serverにアクセスするため、わざとこうしています。

メタデータをダウンロードし、.well-known以下に配置します。

curl -L -o .well-known/oauth-authorization-server https://integrator-******.okta.com/oauth2/*****************/.well-known/oauth-authorization-server


[root@ordsmcp html]# curl -L -o .well-known/oauth-authorization-server https://integrator-********.okta.com/oauth2/***************/.well-known/oauth-authorization-server

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

                                 Dload  Upload   Total   Spent    Left  Speed

100  2624    0  2624    0     0   6219      0 --:--:-- --:--:-- --:--:--  6218

[root@ordsmcp html]# 


以上で全体の設定が完了しました。


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



MCP Inspectorを起動します。

npx @modelcontextprotocol/inspector

Transport TypeStreamable HTTPを選択し、URLにORDSのRESTモジュールとして実装されているサンプルのMCPサーバーのURLを設定します。

https://ホスト名/ords/apexdev/sampleserver/mcp

OAuth 2.0 FlowClient IDに、Oktaに作成した統合アプリORDS MCPクライアントIDを設定します。

2026年2月27日追記 - Scopeの指定が必須になったようです。デフォルトで含まれるはずのopenidScopeに指定します。

Connectをクリックし、認証プロセスを開始します。


Oktaのサインイン画面に遷移します。ユーザー名を入力し、次へ進みます。


このユーザーはOkta Verifyを構成しています。

Okta Verifyのコードを入力し確認します。


パスワードを入力し確認します。


ユーザー認証に成功しました。


以上でRole based JWT profileで保護したORDS REST APIを、MCP Inspectorでアクセスできました。

以下より、ブラウザ版のChatGPTで、このMCPサーバーをアプリとして作成してみます。

ChatGPTはMCP Inspectorとは異なり、oauth-protected-resourceのauthorization_serversを正しく認識するため、JSONオブジェクトではなくJSON配列で設定します。
{
  "resource": "api://ordsmcp",
  "authorization_servers": [
    "https://integrator-*******.okta.com/oauth2/********************"
  ]
}

ChatGPTで認証できるように、統合アプリORDS MCPサインインリダイレクトURIとして、以下を追加します。

https://chatgpt.com/connector_platform_oauth_redirect


ChatGPTのプランに依存すると思いますが(Plusプランで確認しています)ブラウザ版ChatGPTを開発者モードにすると、設定アプリとコネクター高度な設定が表示されます。

アプリを作成するをクリックします。


新しいアプリの名前My Oracle Appとします。説明として「Oracleデータベースに接続しSELECT文を実行します」を記述します。

MCPサーバーのURLは、MCP Inspectorに設定したURLと同じです。

https://ホスト名/ords/apexdev/sampleserver/mcp

認証OAuthを選択し、OAuthクライアントIDに、Oktaに作成した統合アプリORDS MCPのクライアントIDを設定します。(DCR - 動的クライアント登録を構成するとクライアントIDは省略できるはずです。本記事の目的はリソース・サーバー、つまりORDSの構成方法の確認なのでDCRは構成していません。)

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


Oktaの認証プロセスが開始します。サインイン手順はMCP Inspectorと同じなので省略します。


サインインが完了すると、作成したアプリMy Oracle Appが接続します。

アクションとしてツールのget_schemaやrun_sqlが見えているので、OAuthによる認証は成功しています。


ChatGPTの新しいチャットを開始し、My Oracle Appのツールget_schemaを呼び出してみます。

My Oracle Appのget_schemaを呼び出して


ChatGPTでの接続が確認できました。

Claude Desktopではカスタムコネクタとして追加します。

Claude Desktopで認証できるように、統合アプリORDS MCPサインインリダイレクトURIとして、以下を追加します。

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


Claude Desktopでも、ChatGPTと同じ設定でカスタムコネクタを追加します。


追加したカスタムコネクタMy Oracle App連携させます。


Oktaでの認証プロセスが完了すると、使用できるツールが一覧されます。


新規チャットからカスタムコネクタを呼び出してみます。

My Oracle Appのget_schemaを呼び出して


Claude Desktopでも、カスタムコネクタとしてリモートMCPサーバーを呼び出すことができました。

今回の記事は以上です。

2025年12月12日金曜日

Oracle REST Data ServicesのRole based JWT profileによる保護を確認する

Oracle REST Data ServicesのRESTモジュールを保護するJWTプロファイルには、以下の2つの構成があります。
  • スコープ・ベースJWTプロファイル
  • ロール・ベースJWTプロファイル
公式ドキュメントの以下で説明されています。

Oracle REST Data Services, Release 25.3
Developer's Guide

注意12 Developing Oracle REST Data Services Applicationsの先頭にTopicsのリストがありますが、2.9 JWT Profile and JWT Profile RBACはTopicsに含まれていません。Configuring Secure Access to RESTful ServicesJWT Bearer Token Authentication and Authorization Using JWT Profileの間にこのトピックがあります。

注意2:最新のORDSではパッケージOAUTHの代わりにORDS_SECURITYの使用が推奨されています。そのためJWTプロファイルの作成にはORDS_SECURITY.CREATE_JWT_PROFILEを呼び出すべきですが、このAPIのリファレンスにはRBACの実装に必要な引数p_role_claim_nameが含まれていません。OAUTH.CREATE_JWT_PROFILEのリファレンスには引数p_role_claim_nameが含まれています。これはドキュメントの問題で、ORDS_SECURITY.CREATE_JWT_PROFILEは、引数p_role_claim_nameをサポートしています。

公式ドキュメント以外に参考になるドキュメントとして、ORDSのプロダクト・マネージャであるChris Hoinaさんによるブログ記事があります。
Chris Hoinaさんの記事では、テストで使用するアプリケーションをNode.js / Express.js で作成していて、APEXアプリケーション開発者にはハードルが高いです。

本記事では、APEXアプリケーションを使って、ロール・ベースJWTプロファイルによる保護を実装します。以下の記事では、すべてスコープ・ベースJWTプロファイルによって、ORDSのRESTモジュールを保護しています。
それぞれのアイデンティティ・プロバイダにて、スコープ・ベースからロール・ベースJWTプロファイルによる保護に切り替えてみます。

最初に、ORDSのスコープ・ベースJWTプロファイルとロール・ベースJWTプロファイルによる保護の違いを説明します。

スコープ・ベースJWTプロファイルは、ORDS_SECURITY.CREATE_JWT_PROFILEを、引数p_role_claim_name無しで呼び出して作成します。このとき、RESTモジュールを保護するORDSの権限は、ORDS.DEFINE_PRIVILEGEを以下の引数で呼び出して作成します。権限名はmyordsapp、RESTモジュール名はprintとします。

スコープ・ベースJWTプロファイルによる保護では、権限名がアクセス・トークンのscopeまたはscpクレームに含まれていれば、権限に紐づいているRESTモジュールへのアクセスが認可されます。ロールを指定する必要はなく、指定があったとしても認可の可否に影響を与えません。
declare
    l_roles    owa.vc_arr;
    l_modules  owa.vc_arr;
    l_patterns owa.vc_arr;
begin
    l_modules(1) := 'print';
    ords.define_privilege(
        p_privilege_name => 'myordsapp',
        p_roles          => l_roles,      -- no assignment
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/
ロール・ベースJWTプロファイルによる保護では、アクセス・トークンに含まれるロールに、ORDSの権限に紐づけられたロールが含まれていれば、権限に紐づいているRESTモジュールへのアクセスが認可されます。権限名がスコープに含まれている必要はありません。アクセス・トークンのロールを含むクレームは、ORDS_SECURITY.CREATE_JWT_PROFILEの引数p_role_claim_nameに、JSONパスで指定します。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => 'https://sts.windows.net/********-****-****-****-************/'
        ,p_audience => 'api://********-****-****-****-************'
        ,p_jwk_url => 'https://login.microsoftonline.com/********-****-****-****-************/discovery/v2.0/keys'
        ,p_role_claim_name => '/roles'
    );
end;
/
上記ではp_role_claim_nameに/rolesを指定して、JWTプロファイルを作成しています。アクセス・トークンのrolesクレームに、ORDS側でロールとして作成したords_user_roleが含まれていれば、RESTモジュールprintへのアクセスが認可されます。スコープに権限名であるords_user_privilegeが含まれている必要はありません。
declare
    l_roles    owa.vc_arr;
    l_modules  owa.vc_arr;
    l_patterns owa.vc_arr;
begin
    ords.create_role(
        p_role_name => 'ords_user_role'
    );
    l_modules(1) := 'print';
    l_roles(1)   := 'ords_user_role';
    ords.define_privilege(
        p_privilege_name => 'ords_user_privilege',
        p_roles          => l_roles,
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/
ORDSのスコープ・ベースJWTプロファイルとロール・ベースJWTプロファイルによる保護には、以上のような違いがあります。

これらを踏まえて、それぞれのアイデンティティ・プロバイダーごとにロール・ベースJWTプロファイルの保護を実装してみます。すべてのケースで、スコープ・ベースJWTプロファイルによる保護が実装できている状態から作業を始めます。


Microsoft Entra ID



Entra IDのコンソールよりグループを開きます。Entra IDで作成するグループを、ORDSのロールに紐付けます。


新しいグループを作成します。


グループの種類セキュリティを選びます。グループ名ORDSUsersグループの説明は「ORDS REST APIへのアクセスを許可」と記述します。

以上でグループを作成します。


グループORDSUsersが作成されます。

すべてのグループからORDSUsersを開き、メンバーを追加します。


メンバーを開き、メンバーの追加を実行します。


グループに追加するメンバーを選択します。


ページを再ロードし、追加されたメンバーを確認します。


グループORDSUsersの概要を開きオブジェクトIDをコピーします。

ロール名にグループ名であるORDSUsersを使用したいのですが、Entra IDでグループ名をロールに含める方法を見つけられませんでした。そのため、ロール名にオブジェクトID(グループID)を使用します。


アプリケーションORDS JWT Testトークン構成を開きます。

グループ要求の追加を実行します(翻訳はグループ要求ですが、ここでの要求はclaimのことで、groups claimの追加という意味です。)


ドロワーとして、グループの要求の編集が開きます。

先ほど作成したグループORDSUsersタイプセキュリティなので、アクセス、ID、SAMLトークンに含めるグループの種類を選択してください、のセキュリティチェックします。

種類別にトークンのプロパティをカスタマイズする、ではIDアクセスともにグループIDを選択し、グループをロール要求として生成するをチェックします。

グループID以外を選択して動作を確認しましたが、何を設定してもアクセス・トークンにはグループ名ではなくグループIDがrolesクレームに含まれていたため、グループIDを選択しています。

グループをロール要求として生成するをチェックすると、アクセス・トークンにはrolesクレームにグループが含まれるようになります。未チェックの場合は、groupsクレームにグループが含まれます。ORDS_SECURITY.CREATE_JWT_PROFILEのp_role_claim_name/rolesと指定するか/groupsと指定するかの違いになりますが、今回はチェックを入れて、rolesクレームとなるようにしています。

詳しく調べていませんが、IDトークンとアクセス・トークンで異なる設定をすると、どちらかの設定が優先されるような動作になりました。IDトークンとアクセス・トークンで設定を変える必然性はないと思うので、同じ設定にするのが望ましいでしょう。

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


オプションの要求としてgroupsが追加されます。


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

ORDSのRESTモジュールを、ロール・ベースJWTプロファイルによる保護に変更します。

スコープ・ベースで保護されている状態で、APEXアプリケーションにサインインします。アクセス・トークンにrolesクレームとして、グループIDの配列が含まれていることが確認できます。
  "roles": [
    "aeb7eee2-b1ee-4127-91b5-58aaa9df63bd",
    "aa5a12e0-9c13-4a01-9a3f-95f978f2ce06"
  ],

ロール・ベースのJWTプロファイルを設定します。引数p_role_claim_name/rolesの指定を追加して、ORDS_SECURITY.CREATE_JWT_PROFILEを呼び出します。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => 'https://sts.windows.net/********-****-****-****-************/'
        ,p_audience => 'api://********-****-****-****-************'
        ,p_jwk_url => 'https://login.microsoftonline.com/********-****-****-****-************/discovery/v2.0/keys'
        ,p_role_claim_name => '/roles'
    );
end;
/

スコープ・ベースからロール・ベースの保護に切り替わりました。そのため、APEXアプリケーションをリロードすると、REST API Responseの表示はUnauthorizedに変わります。


ロール名がグループORDSUsersのグループIDであるロールを作成し、そのロールとRESTモジュールprintを紐づけた権限として、ORDSUsesを作成します。権限名のORDSUsersをアクセス・トークンのスコープに含む必要はありません。
declare
    l_roles    owa.vc_arr;
    l_modules  owa.vc_arr;
    l_patterns owa.vc_arr;
begin
    ords.create_role(
        p_role_name => 'aa5a12e0-9c13-4a01-9a3f-95f978f2ce06'
    );
    l_modules(1) := 'print';
    l_roles(1)   := 'aa5a12e0-9c13-4a01-9a3f-95f978f2ce06';
    ords.define_privilege(
        p_privilege_name => 'ORDSUsers',
        p_roles          => l_roles,
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/

上記の権限ORDSUsersが作成されるとREST APIの呼び出しは認可され、REST API Responseに呼び出し結果が表示されます。


以上でロール・ベースJWTプロファイルによる保護に切り替わったので、スコープ・ベースの設定は削除できるはずです。実際、ORDSの権限myordsappは削除できます。

ただし、認証スキーム有効範囲に設定したアプリケーションのURIを含むカスタム・スコープapi://********-****-****-****-****-***********/myordsappを削除すると、アクセス・トークンのiss属性やaud属性が変わる上に、rolesクレームがアクセス・トークンに含まれなくなります。結果として、RESTモジュールprintへのアクセスが認可されません。


認証スキーム有効範囲からカスタム・スコープを削除したいのですが、Microsoft Entra IDでどのようにすれば良いのかは、今のところ見つけられていません。


Okta



OktaのAdmin Consoleよりグループを開き、グループを追加します。


グループの名前ORDSUsers説明は「ORDS REST APIへのアクセスを許可」と記述します。

保存をクリックします。


グループに再度アクセスし、グループ一覧を更新します。

作成したグループORDSUsersを開き、ユーザーを割り当てます。


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


グループORDSUsersにユーザーを割り当てます。


ユーザーの割り当てを完了します。


セキュリティAPIより、作成済みの認可サーバーORDSを開きます。


クレームタブを開き、クレームを追加します。


追加するクレームの名前rolesとします。トークンタイプに含めるアクセス・トークンです。

値タイプグループを選択し、フィルター次で始まるORDSを設定します。このフィルターにより、rolesクレームに先ほど作成したグループORDSUsersが含まれます。

クレームを無効化チェックせず含めるいずれかのスコープを選択します。

以上で作成します。


以上でOktaの設定は完了です。

ロール・ベースJWTプロファイルを設定します。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => 'https://integrator-********.okta.com/oauth2/******************'
        ,p_audience => 'api://ords'
        ,p_jwk_url => 'https://integrator-********.okta.com/oauth2/******************/v1/keys'
        ,p_role_claim_name => '/roles'
    );
end;
/

スコープ・ベースからロール・ベースの保護に切り替わりました。そのため、APEXアプリケーションをリロードすると、REST API Responseの表示はUnauthorizedに変わります。

User Infoに表示されているアクセス・トークンの内容に、rolesクレームとして、ORDSUsersが含まれていることが確認できます。


ロールとしてORDSUsersを作成し、そのロールとRESTモジュールprintを紐づけた権限として、ORDSUsesを作成します。権限名のORDSUsersをアクセス・トークンのスコープに含む必要はありません。
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) := 'print';
    l_roles(1)   := 'ORDSUsers';
    ords.define_privilege(
        p_privilege_name => 'ORDSUsers',
        p_roles          => l_roles,
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/

上記の権限ORDSUsersが作成されるとREST APIの呼び出しは認可され、REST API Responseに呼び出し結果が表示されます。


Oktaの場合は、認証スキーム有効範囲からスコープmyordsappを削除できます。


また、ORDSの権限myordsappも不要なので削除できます。


Oktaの認可サーバーORDSに設定したスコープmyordsappも同様に削除できます。



Auth0


Auth0は趣が異なっていて、スコープ・ベースでもロール・ベースでも、Auth0側の設定は同じです。

Auth0で作成するのはパーミッションであり、パーミッションとして設定した名前が、スコープとpermissionsクレームに含まれます。Auth0のアクセス・トークンは以下のようになっています。
{
  "iss": "https://dev-************.us.auth0.com/",
  "sub": "google-oauth2|******************",
  "aud": [
    "api://ords/",
    "https://dev-************.us.auth0.com/userinfo"
  ],
  "iat": 1765528368,
  "exp": 1765614768,
  "scope": "openid profile myordsapp",
  "azp": "J3FejeK46E2EH8AhsDq53HylfgB30wyJ",
  "permissions": [
    "myordsapp"
  ]
}
そのため、ORDS側ではAuth0に作成したパーミッションmyordsappをscopeとして評価することもできるし、permissionsクレームに含まれた名前として評価することもできます。

以上よりAuth0の設定は変更せず、引数p_role_claim_name/permissionsを指定して、ロール・ベースJWTプロファイルを作成します。
begin
    ords_security.delete_jwt_profile;
    ords_security.create_jwt_profile(
        p_issuer => 'https://dev-************.us.auth0.com/'
        ,p_audience => 'api://ords/'
        ,p_jwk_url => 'https://dev-************.us.auth0.com/.well-known/jwks.json'
        ,p_role_claim_name => '/permissions'
    );
end;
/

permissionsクレームに含まれる名前myordsappを、ORDS側でロールとして作成します。
declare
    l_roles    owa.vc_arr;
    l_modules  owa.vc_arr;
    l_patterns owa.vc_arr;
begin
    ords.create_role(
        p_role_name => 'myordsapp'
    );
    l_modules(1) := 'print';
    l_roles(1)   := 'myordsapp';
    ords.define_privilege(
        p_privilege_name => 'ORDSUsers',
        p_roles          => l_roles,
        p_modules        => l_modules,
        p_patterns       => l_patterns    -- no assignment
    );
end;
/

 以上でORDSのRESTモジュールの保護がスコープ・ベースからロール・ベースに変更されました。

スコープは使用しないので、APEXアプリケーションの認証スキーム有効範囲からmyordsappを削除できます。


ORDSに権限として作成されているmyordsappも削除できます。


今回作成した権限ORDSUsersによって、RESTモジュールprintが保護されます。ロールとしてmyordsappを作成しています。


以上で、権限ORDSUsersによりREST APIの呼び出しは認可され、REST API Responseに呼び出し結果が表示されます。


Auth0にはロールの設定がありますが、これはパーミッションをまとめてユーザーに割り当てられるようにするための設定で、アクセス・トークンのpermissionsクレームには直接かロール経由かに関わらず、パーミッションの名前だけが含まれるようです。そのため、ORDSの保護という面では、意識する必要はなさそうです。

Oracle IAMについては、以下の記事で確認しています。

Oracle IAMの統合アプリにカスタム・クレームを追加しRole based JWT profileによる保護を確認する
https://apexugj.blogspot.com/2025/12/protecting-ords-by-role-based-jwt-profile-with-oracle-iam.html

今回の記事は以上になります。

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