How To Generate & Use OCI Pre-Authenticated Requests from APEX

Search for a command to run...

Thanks Jon, excellent yet again - just what I needed. I never was happy about dynamically copying files into an OCI pre-authenticated tmp folder for browser access. This looks like the correct approach, cheers
Introduction One of the marquee features of APEX 26.1 was AI Interactive Reports. When I started testing this new feature, I was interested to see what was going on behind the scenes. In this post, I

Introduction One of the marquee features of APEX 26.1 is APEX AI Agents. APEX AI Agents allow you to use an LLM and your own PL/SQL and JS tools to perform actions on your data instead of just chattin

Introduction In my previous post, I looked at logging APEX AI Agent requests and responses with Request and Response handlers. Logging is the first step because it shows you what is actually moving th

Introduction Logging is one of the first things you need when building serious AI Agents. Without it, debugging quickly becomes guesswork. You can see the final answer, but not always why the model ch

Context management patterns from building agents in Oracle APEX

Sometimes you need to give a user or another system temporary access to get or upload files from/to Oracle Cloud Infrastructure (OCI) Object Storage. This temporary access is achieved using Pre-Authenticated Requests. Pre-Authenticated Requests (PARs) are pre-signed URLs that provide temporary access to read or write files from/to a specified bucket or a specified path within a bucket. This post will show you how to generate and consume PARs from within your APEX Applications.
Pre-Authenticated Requests should be used with caution. A PAR URL gives anyone with the URL access to the Object Store resources identified in the request.
You can create a pre-authenticated request that grants read, write, or read/write access to one of the following:
For PARs that apply to multiple objects, you can also decide whether you want to let users list those objects.
I created a PL/SQL package and function which allows you to generate OCI Pre-Authenticated requests from APEX. You can download it from my Github repository.
This section will describe the Oracle Cloud Infrastructure (OCI) setups required for this solution.
Please refer to my previous post Secure APEX Access to OCI Object Storage. This post will show you how to perform the following configurations in the OCI Console. I will reference the configuration names in quotes throughout this blog post:
Once you have completed the steps from the previous section, create the following additional Policy in the same OCI Compartment.

The first policy statement: Allow group APEX_OCI_BLOG_Security_Group manage buckets in compartment APEX_OCI_BLOG where all {target.bucket.name='APEX_OCI_BLOG_FILES', any {request.permission='PAR_MANAGE'}}, allows users that belong to the APEX_OCI_BLOG_Security_Group to create PARs in the APEX_OCI_BLOG_FILES bucket.
The second policy statement: Allow group APEX_OCI_BLOG_Security_Group to manage objects in compartment APEX_OCI_BLOG where all {target.bucket.name='APEX_OCI_BLOG_FILES', any {request.permission='OBJECT_CREATE', request.permission='OBJECT_READ',request.permission='OBJECT_OVERWRITE'}}, allows users that belong to the APEX_OCI_BLOG_Security_Group to create, update and read objects in the APEX_OCI_BLOG_FILES bucket.
As the documentation mentions, not only must the user have access to create PARs, but they must also have permission to perform the actions passed on in the PAR (i.e., OBJECT_CREATE, OBJECT_READ, etc.). You can adjust the permissions in the second policy statement to suit your use case.
This section will examine the PL/SQL code and APEX configurations needed to support this solution.
Please refer to my previous post Secure APEX Access to OCI Object Storage. This post describes creating a Web Credential in APEX for your OCI Service Account. For this post, the Web Credential static ID is APEX_OCI_BLOG_CREDENTIAL.
In the package cndemo_oci_pre_auth_requests_pk you will see a function called generate_pre_auth_request. This function can be called from APEX to generate a PAR URL. You can see example calls to this function later in this post.
The PL/SQL block below borrows the logic from the function generate_pre_auth_request and makes it available in a PL/SQL block. The in-line comments describe what the code is doing.
OCI REST Service Documentation Links
Now that we can generate PARs, how do we use these secured URLs to get and upload files from/to OCI Object Store? This section describes two examples, one to write files to a folder in a bucket and another to get a specific file from a particular folder.
In this example, we generate a PAR to allow customers to upload files to Object Store using a secured URL.
Code to generate PAR for this example:
DECLARE
l_par_url VARCHAR2(1000);
BEGIN
l_par_url := cndemo_oci_pre_auth_requests_pk.generate_pre_auth_request
-- PAR will expire in 1 Hour
(p_expiration_unit => 'HOUR',
p_expiration_value => 1,
-- PAR allows the holder of the URL to create any file
p_access_type => 'AnyObjectWrite',
-- PAR restricts the holder of the URL to create files in the PAR_TEST_FOLDER folder
p_object_name => 'PAR_TEST_FOLDER',
-- PAR allows the holder to list files in the folder PAR_TEST_FOLDER.
p_object_listing => 'ListObjects');
dbms_output.put_line ('URL: '||l_par_url);
END;
-- Parameters:
-- p_expiration_unit Values: [DAY,HOUR,MINUTE,SECOND]
-- p_expiration_value Number of p_expiration_unit used to calculate URL expiration time.
-- p_access_type Permissions: [ObjectRead, ObjectWrite, ObjectReadWrite, AnyObjectWrite, AnyObjectRead, AnyObjectReadWrite]
-- p_object_name Object name or Prefix of objects in the bucket that URL has access to.
-- p_object_listing Allow URL to list-objects. Values: [Deny,ListObjects]
PAR Generated by the above code: https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/
In our example, we need to append the folder name (p_object_name) and the name we want the file to be called when uploaded to the folder. The completed URL looks like this:
https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Dark.png
The screenshot below shows how you can upload a file using the above PAR in Postman:

Here is the curl generated by Postman:
curl --location --request PUT 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Dark.png' \
--header 'Content-Type: image/png' \
--data-binary '@/Users/jdixon/Documents/Technical/My Blogs/Graphics/APEX Logos/APEX_Logo_Dark.png'
Here is a screenshot of the file that was uploaded to OCI Object Store:

In this example, we are generating a PAR to allow customers to download a specific file from a particular folder in Object Store.
Here is a screenshot of the file we want holders of the PAR to access:

Code to generate PAR for this example:
DECLARE
l_par_url VARCHAR2(1000);
BEGIN
l_par_url := cndemo_oci_pre_auth_requests_pk.generate_pre_auth_request
-- PAR will expire in 1 Hour
(p_expiration_unit => 'HOUR',
p_expiration_value => 1,
-- PAR allows the holder of the URL to get a file
p_access_type => 'ObjectRead',
-- PAR is restricted to the APEX_Logo_Light.png file
-- in the PAR_TEST_FOLDER folder.
p_object_name => 'PAR_TEST_FOLDER/APEX_Logo_Light.png',
-- PAR does not allow the holder to list files.
p_object_listing => 'Deny');
dbms_output.put_line ('URL: '||l_par_url);
END;
PAR Generated by the above code: https://objectstorage.us-ashburn-1.oraclecloud.com/p/q7CeVldJj7d5pabY16kTWsREfr8NgjTRMAbBpNpBmAIPT2KYCyvIJK4o77fKqbrx/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png
The screenshot below shows how to get the file using the above PAR in Postman:

Here is the curl generated by Postman:
curl --location --request GET 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/q7CeVldJj7d5pabY16kTWsREfr8NgjTRMAbBpNpBmAIPT2KYCyvIJK4o77fKqbrx/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png'
Using a PAR URL to get a file from PL/SQL is easy with apex_web_service.make_rest_request_b
DECLARE
l_par_url VARCHAR2(1000);
l_response_blob BLOB;
BEGIN
-- For a GET, use the complete URL returned from generating the PAR
l_par_url := 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/6gLghRVH8_NqRy2goZdhp-p0Ifr5JlR2YrkBObNjBJ2BmSS1s5hXysgzoFFV7WOX/n/test/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png';
-- No additional authentication or credentials are required
l_response_blob := apex_web_service.make_rest_request_b
(p_url => l_par_url,
p_http_method => 'GET');
dbms_output.put_line ('File Size: '||dbms_lob.getlength(l_response_blob));
END;
In this post, I described how Pre-authenticated requests allow you to provide temporary secure access to read or write files from/to OCI Object Store. I also showed you how you can generate and consume Pre-authenticated requests directly from your APEX applications.