Oracle News

How to Secure Oracle ORDS 25.4 APIs with OAuth (Client Credentials): Step-by-Step Guide

Learn how to secure Oracle ORDS REST APIs using OAuth 2.0 Client Credentials. Step-by-step guide, SQL examples, and best practices for enterprise security.

How to Secure Oracle ORDS 25.4 APIs with OAuth (Client Credentials): Step-by-Step Guide

If you are exposing REST endpoints using Oracle REST Data Services (ORDS), securing them properly is critical, especially for integrations, SaaS platforms, and enterprise APIs.

In this guide, we’ll walk through how to:

  • Create a REST module in ORDS 25.4
  • Protect it using ORDS Roles and Privileges
  • Enable OAuth client_credentials authentication
  • Generate tokens using curl
  • Call the secured API endpoint

This example uses safe placeholder values (no real credentials).

Architecture Overview

We will create:

  • Module: myapi
  • Endpoint:
    POST https://api.example.com/ords/myapi/hello
  • ORDS Role: MYAPI_ROLE
  • ORDS Privilege: MYAPI_PRIV
  • OAuth client: myapi_client
  • Grant type: client_credentials

Step 1: Enable the Schema for ORDS

enable_schema.sql
begin
  ords.enable_schema(
    p_enabled             => true,
    p_schema              => 'MYAPI',
    p_url_mapping_type    => 'BASE_PATH',
    p_url_mapping_pattern => 'myapi',
    p_auto_rest_auth      => false
  );
  commit;
end;
/

Step 2: Create the ORDS Module

create_ords_module.sql
begin
  ords.define_module(
    p_module_name    => 'myapi',
    p_base_path      => '/myapi/',
    p_items_per_page => 25,
    p_status         => 'PUBLISHED'
  );
  commit;
end;
/

Step 3: Create Template and POST Handler

Create_Template_and_POST_Handler.sql
begin
  ords.define_template(
    p_module_name => 'myapi',
    p_pattern     => 'hello'
  );

  ords.define_handler(
    p_module_name => 'myapi',
    p_pattern     => 'hello',
    p_method      => 'POST',
    p_source_type => ords.source_type_plsql,
    p_source      => q'[
begin
  owa_util.mime_header('application/json', false);
  owa_util.http_header_close;
  htp.p('{"message":"Secure Hello World"}');
end;
]'
  );

  commit;
end;
/

At this point, the endpoint works, but it is not protected.

Step 4: Protect the API with Role and Privilege

Create a role:

create_role.sql
begin
  ords.create_role(p_role_name => 'MYAPI_ROLE');
  commit;
end;
/

Create privilege:

create_priv.sql
begin
  ords.create_privilege(
    p_name        => 'MYAPI_PRIV',
    p_role_name   => 'MYAPI_ROLE',
    p_label       => 'My API Access'
  );
  commit;
end;
/

Map privilege to URL:

map_priv.sql
begin
  ords.create_privilege_mapping(
    p_privilege_name => 'MYAPI_PRIV',
    p_pattern        => '/myapi/*'
  );
  commit;
end;
/

Attach privilege to module:

attach_priv_2_module.sql
begin
  ords.set_module_privilege(
    p_module_name    => 'myapi',
    p_privilege_name => 'MYAPI_PRIV'
  );
  commit;
end;
/

Now, calling the endpoint without authentication returns: HTTP/1.1 401 Unauthorized

Step 5: Enable OAuth Client Credentials

Your DBA, or whoever operates your Oracle APEX and ORDS hosting, must grant:

SQL
grant execute on ords_metadata.oauth_admin to MYAPI;
grant execute on ords_metadata.oauth to MYAPI;

Then create OAuth client:

create_oauth_client.sql
begin
  ords_metadata.oauth_admin.create_client(
    p_schema          => 'MYAPI',
    p_name            => 'myapi_client',
    p_grant_type      => 'client_credentials',
    p_owner           => 'MYAPI',
    p_description     => 'Client credentials for My API',
    p_origins_allowed => null,
    p_redirect_uri    => null,
    p_support_email   => 'support@example.com',
    p_support_uri     => 'https://example.com',
    p_privilege_names => 'MYAPI_PRIV'
  );
  commit;
end;
/

Grant role to the OAuth client:

grant_role_2_oauth_client.sql
begin
  ords_metadata.oauth_admin.grant_client_role(
    p_schema      => 'MYAPI',
    p_client_name => 'myapi_client',
    p_role_name   => 'MYAPI_ROLE'
  );
  commit;
end;
/

Retrieve client_id and client_secret:

SQL
select name, client_id, client_secret
from ords_metadata.user_ords_clients
where upper(name) = 'MYAPI_CLIENT';

Step 6: Get OAuth Token Using curl

Bash
curl -s -u '<client_id>:<client_secret>' \
  -d 'grant_type=client_credentials' \
  "https://api.example.com/ords/myapi/oauth/token"

Example response:

JSON
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600
}

Step 7: Call the Secured Endpoint

Bash
TOKEN="<access_token>"

curl -i -X POST \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.example.com/ords/myapi/hello"

Expected response:

Bash
HTTP/1.1 200
Content-Type: application/json

{"message":"Secure Hello World"}

Why Use OAuth Client Credentials for ORDS APIs?

  • No database password exposure
  • Token expiration control
  • Clean integration model for SaaS
  • Easy secret rotation
  • Industry-standard OAuth 2.0

Best Practices for Production ORDS Security