Two Methods of Setting an APEX Authentication Scheme at Run-Time

Two Methods of Setting an APEX Authentication Scheme at Run-Time

·

9 min read

Introduction

Before APEX 23.1, there was only one way to set the Authentication Scheme at run-time: via a URL and the request APEX_AUTHENTICATION. In APEX 23.1, you have another option: to identify a Configuration Procedure that APEX uses to set the Authentication Scheme dynamically.

In this post, I will review the existing URL and Request method and provide details on the new Configuration Procedure approach. I will also discuss the benefits of each approach as I go along.

Pre-Requisites

Both approaches require you to set the Switch in Session flag to 'Yes' for any Authentication scheme you want to switch to.

APEX Dynamic Authentication Scheme Switch in Session

You should also note that these approaches are mutually exclusive. You can use the URL Request Approach or the Configuration Procedure approach, but not both.

Use Case

I will use the following Authentication Schemes to demonstrate the two approaches. Each Authentication Scheme has a different Scheme Type, which becomes important for the Configuration Procedure approach.

APEX Dynamic Authentication Scheme Use Cases

URL Request Approach

With this approach, you must call an APEX page with a request of APEX_AUTHENTICATION and assign the name of the Authentication Scheme you want to switch to.

Using this approach, there are two ways to set the request. One is to Construct a URL, and the other is to use a Button.

Constructing a URL

If you need to access your Application directly from a URL (and set the Authentication Scheme), then you can construct the URL as follows.

-- Traditional URL
https://example.com/ords/f?p=201:1::APEX_AUTHENTICATION=OFFICE365
-- Freindly URL
https://example.com/ords/r/demo/blog-demo/home?request=APEX_AUTHENTICATION=OFFICE365

These URLs point to the home page (Page ID: 1, Page Alias: home). They are both setting the Authentication scheme to OFFICE365. For this particular authentication scheme, the user will be automatically re-directed to log in to Office 365 (if not already logged in) and then, once logged in, re-directed to the home page. It will work the same way for the example Okta Authentication Scheme. For the APEX Accounts scheme, the user would be directed to the login page to enter their APEX credentials.

When to Use This Approach

  • If you have a portal or static website from which your users access your App, and you know the Authentication Scheme you want to use in advance.

  • You are accessing your APEX Application from another application. For example, if you are accessing your APEX App from a link in a SaaS application.

From a Button

Another approach is to set the request from a button on your login page.

APEX Dynamic Authentication Scheme Set Request from Button

The 'Sign in with Microsoft' button is configured as follows. When the user clicks the button, APEX sets the Authentication scheme to 'OFFCIE365', then attempts to re-direct to page 1. After this, the remaining authentication steps are the same as for the URL method above.

APEX Dynamic Authentication Scheme Set Request from Button Config

When to Use This Approach?

  • If you have an APEX login page and you want to give your users a choice in how they want to log in to your Application using buttons (like the above screenshot).

Configuration Procedure Approach

Now, to the APEX 23.1 Configuration Procedure approach. The short version is that you can create a PL/SQL procedure (the Configuration Procedure) that will be called when APEX creates a new session. Within this procedure, you can tell APEX which Authentication scheme you want it to use (and some other things that I will get to shortly).

Example Scenario

To help explain how this works, I will walk through an example I have encountered several times. Let's take an APEX SaaS application where we want to separate the data for each Tenant (or customer) that uses the Application. I touched on this subject previously in my blog post Building Multi-Tenant APEX Apps.

Let's say we have three tenants using our APEX SaaS application.

  • Tenant A wants users to sign in using their Office 365 credentials and their Office 365 environment. i.e., The Tenant's IT department creates an App Registration in Active Directory and generates their own Client ID and Client Secret, which you include in an APEX Web Credential with a static ID of OFFICE365.

  • Tenant B wants users to sign in using their own Okta instance. The Tenant's IT department creates its own Client ID and Client Secret, which you include in an APEX Web Credential with a static ID of OKTA_TENANTA.

  • Tenant C wants their users to register with your Okta tenant, and you generate a Client ID and Secret from your Okta instance, which you include in a Web Credential with a static ID of OKTA_CLOUD_NUEVA.

Each Tenant accesses our Application with a different sub-domain, as follows:

TenantURL Prefix
Ahttps://tenanta.example.com/ords/saasapp
Bhttps://tenantb.example.com/ords/saasapp
Chttps://tenantc.example.com/ords/saasapp

Before this new Configuration Procedure approach came along, you would have had to create an Authentication Scheme for each of the three tenants (as well as an APEX Web Credential for each Authentication Scheme).

APEX Setups

Web Credentials

For our example, we need three web credentials:

APEX Dynamic Authentication Scheme Example Web Credentials

Authentication Schemes

For our example, we need just two Authentication Schemes. One for Office 365 and one for Okta. How can this be, you say, the Credential Store and Discovery URLs will be different for each Tenant? Don't worry; we will get into that.

Office 365 Authentication Scheme

APEX Dynamic Authentication Scheme Office 365 Authentication Scheme

Okta Authentication Scheme

APEX Dynamic Authentication Scheme Okta Authentication Scheme

📣
Being able to switch the Credential Store and Discovery URL dynamically is an important difference between this approach and the URL approach. This means we only need to configure one Authentication Scheme per authentication provider and utilize multiple Discovery URLs and Web Credentials to provide authentication access to different instances of that authentication provider.

Create a PL/SQL Procedure

The next step is to create a PL/SQL Procedure to dynamically set the Authentication Scheme, APEX Web Credential, and Discovery URL. I have hard-coded the logic in the example procedure below to make things easier to understand. You should store these values in a table.

CREATE OR REPLACE PROCEDURE cn_set_auth_scheme
  (p_conf in out nocopy apex_authentication.t_configuration) AUTHID DEFINER IS

  l_log_prfx             VARCHAR2(500)  := 'cn.cn_set_auth_scheme';
  l_tenant_host          VARCHAR2(1000) := sys.owa_util.get_cgi_env('HTTP_HOST');

BEGIN

  -- l_tenant_host captures the host name of the URL used to 
  --   access the application e.g. tenanta.example.com
  apex_debug.info('%s - In Select Auth [%s]', l_log_prfx, l_tenant_host);

  -- This logic is for illustration purposes only, these values
  --  should really be stored in a table.
  CASE 
    WHEN l_tenant_host LIKE '%tenanta.%' THEN
      -- We only have one Credential for Office 365.
      p_conf.authentication_name := 'OFFICE365';
      -- Even though we do not need to dynamically set the
      --   CREDENTIAL_STATIC_ID, we must still provide it, or 
      --   we will get an error.
      p_conf.substitutions := apex_t_varchar2
       ('CREDENTIAL_STATIC_ID', 'OFFICE365');
      -- We can also set the Tenant ID for the current session.
      --  This is the same as calling apex_session.set_tenant_id.
      --  In this case tenanta has a tenant_id of 1.
      p_conf.tenant_id := 1;
    WHEN l_tenant_host LIKE 'tenantb.%' THEN
      -- Both Tenant B & C can use the OKTA Authentication Scheme.
      p_conf.authentication_name := 'OKTA';
      -- For Tenant B, we need to dynamically set the Web Credential to 
      --   'OKTA_TENANTA'. We also need to change the discovery URL 
      --   which is specific to each Okta instance.
      p_conf.substitutions := apex_t_varchar2
       ('CREDENTIAL_STATIC_ID', 'OKTA_TENANTA',
        'DISCOVERY_URL', 'https://dev-1111111.okta.com/.well-known/openid-configuration');
      p_conf.tenant_id := 2;
    WHEN l_tenant_host LIKE 'tenantc.%' THEN
      -- Both Tenant B & C can use the OKTA Authentication Scheme.
      p_conf.authentication_name := 'OKTA';
      -- For Tenant C, we need to dynamically set the Web Credential to 
      --   'OKTA_CLOUD_NUEVA'. We also need to change the discovery URL 
      --   which is specific to each Okta instance.
      p_conf.substitutions := apex_t_varchar2
       ('CREDENTIAL_STATIC_ID', 'OKTA_CLOUD_NUEVA',
        'DISCOVERY_URL', 'https://dev-2222222.okta.com/.well-known/openid-configuration');
      p_conf.tenant_id := 3;
   END CASE;

EXCEPTION WHEN OTHERS THEN
  apex_debug.error('%s - Unhandled Error [%s]', l_log_prfx, SQLERRM);
  RAISE;
END cn_set_auth_scheme;
💡
Even if you don't need to change the CREDENTIAL_STATIC_ID from the one in the Authentication Scheme, you must still set it in the configuration; otherwise, you will get an error when the procedure runs.

Setting the Tenant ID

Notice that I also set the tenant_id in the above procedure. This is the equivalent of calling the PL/SQL API apex_session.set_tenant_id. Setting this value is optional, but if you need to set it, it makes perfect sense to set it here.

Substitutions

Thank you to Patrick Wolf for clarifying in this forum post.

APEX also allows you to add your own substitutions. Let's take this Authentication Scheme as an example.

I have defined my own substitution variable #DISCOVERY_URL#. I can set this value in the Configuration Procedure as follows:

p_conf.substitutions := apex_t_varchar2
  ('DISCOVERY_URL', 'https://dev-2222222.okta.com/.well-known/openid-configuration');

When APEX runs the Configuration Procedure, assuming I set select this Authentication Scheme using p_conf.authentication_name := 'OFFICE365'; APEX will replace my substitution variable #DISCOVERY_URL# with https://dev-2222222.okta.com/.well-known/openid-configuration and then execute the Authentication Scheme using this value for the Discovery URL.

When is the Procedure Called?

The documentation mentions that the APEX engine may call this procedure at other times, not just during authentication.

In my testing, during authentication, this procedure was called four times before the Post Authentication procedure was called and once afterward. It was also called once for every page refresh and once during log out. Because it is called so frequently, you need to make sure any code you have in this procedure is highly tuned.

Notably, the documentation mentions that the procedure should return the same values in p_conf every time it is called for a given session. I tried changing the return values after a session was established and received the error 'The tenant id already exists for the current session.'

Set the Configure Procedure

Now, we can configure the Application using the PL/SQL procedure defined above. Navigate to Application> Shared Components > Security Settings > (Security Tab), and add your procedure name. In my case, it is cn_set_auth_scheme. In reality, this procedure should be in a PL/SQL package, not defined as a stand-alone procedure.

Oracle APEX Dynamic Authentication Scheme Configuration

As mentioned previously, you can no longer use the URL Approach if you set this value.

What Happens When You Run the App?

In my example, when you run the Application with the URL https://tenanta.example.com/ords/saasapp, APEX will automatically determine the Authentication Scheme applicable for Tenant A (OFFICE365) and then direct you to the Office 365 login process.

If you use the URL https://tenantb.example.com/ords/saasapp, APEX will automatically determine the Authentication Scheme applicable for Tenant B (OKTA_TENANTA) and then direct you to Okta to perform the login process.

Other Uses for this Approach

Even if you don't have a Multi-Tenant use case, you could also use this approach to automatically switch the APEX Web credential used for logging in to your various instances, e.g., DEV, TEST, PROD. This way, you can have different Office 365, Okta, etc. App Registrations for each of your instances.

Conclusion

Although there are still use cases where the URL Request method makes sense, the Configuration PL/SQL Procedure approach represents another important step to making APEX work seamlessly with Multi-Tenant APEX applications. As a bonus, it also reduces the number of Authentication Schemes we need to create for our Multi-tenant applications.

🔗 Read More