Difficulty: Intermediate
TL;DR Problem: Enterprise users need SSO into an APEX app, but SAML callbacks are blocked on managed ORDS (HTTP 403 / ORDS-13002), so the obvious path dead-ends. Stack: Oracle APEX on Autonomous Database (ATP), Oracle-managed ORDS, Microsoft Entra ID (Azure AD), OpenID Connect. Who should read: Anyone wiring a customer-facing or internal APEX app to corporate identity on a managed ATP instance — especially after hitting the SAML 403 wall.
Tested on: Oracle APEX 24.2.17, ORDS Oracle-managed on Autonomous Database (ATP 26ai, Always Free), Microsoft Entra ID. Requires Entra admin (App registrations) and APEX Workspace admin. <!– WORDPRESS: insert a File block here (Add block → File). Upload APEX-Entra-OIDC-Login-Guide.pdf to Media, select it, enable “Show download button”. Suggested link text: “Download the full step-by-step guide (PDF)”. The line below is a placeholder for non-WordPress renders — delete it once the File block is in place. –>
Business Challenge
We are building an APEX application on Autonomous Database to manage a customer’s subscription-related data. One requirement landed early: corporate single sign-on. Every authenticated employee should open the app with their existing Microsoft credentials, with a handful of privileged pages restricted to named administrators — no second password, no local account to provision, no help-desk ticket to onboard a user.
This post documents the login pattern as we proved it in the prototype on an Always Free ATP instance, ahead of rolling it into the customer’s solution. The instinctive route was SAML, because the organization already federated other apps that way. On a managed Autonomous Database that route fails. ORDS is Oracle-managed, so you cannot set security.externalSessionTrustedOrigins. SAML’s callback is a cross-origin POST, and ORDS blocks it with HTTP 403 / ORDS-13002. Per Oracle’s documentation, SAML Sign-In on Autonomous Database is supported only with a customer-managed ORDS — which means standing up and maintaining your own ORDS tier just to log in.
We didn’t want that operational burden, so we built OIDC instead. OIDC uses a redirect-based authorization-code flow that never triggers the cross-origin block, so it works on the default managed ORDS with nothing extra to run. We proved out two variants: a direct path (APEX → OIDC → Entra) and a brokered path (APEX → OIDC → OCI Identity Domain → SAML → Entra) for the case where one identity hub should front several IdPs.
Why OIDC, not SAML
SAML on managed ATP is a dead end unless you take over ORDS. OIDC’s authorization-code redirect flow sidesteps the cross-origin block entirely, so “Log in with Microsoft” works on the stock managed instance — choose SAML only when it’s a hard organizational mandate, and then budget for customer-managed ORDS.
Solution Overview
- Register an App Registration in Entra (this is a different object from a SAML “Enterprise Application” — don’t reuse one).
- Capture the Application (client) ID and Directory (tenant) ID, and create a client secret.
- Grant the APEX schema a network ACL out to the Microsoft endpoints.
- Create an APEX Web Credential holding the client ID and secret.
- Create a Social Sign-In authentication scheme pointed at Entra’s discovery URL.
- Gate the app with Application Access Control — open entry to any authenticated user, role-gate the privileged pages.
- (Optional) Broker through an OCI Identity Domain instead of talking to Entra directly.
Implementation Details
1. Entra App Registration
In the Entra admin center, go to App registrations → New registration. Name it (e.g. APEX OIDC Login), pick single-tenant, and set the Redirect URI as platform Web:
https://<host>.adb.<region>.oraclecloudapps.com/ords/apex_authentication.callback
APEX uses a single OAuth/OIDC callback of the form https://<host>/ords/apex_authentication.callback. From the registration Overview, copy the Application (client) ID (not the Object ID, not the tenant ID) and the Directory (tenant) ID.
Under Certificates & secrets → New client secret, set an expiry and copy the secret Value immediately — it is shown only once. Record the expiry date; you will rotate against it.
Under API permissions, ensure delegated Microsoft Graph openid, profile, and email are present and admin-consented.
APEX needs only the discovery endpoint; it reads authorize, token, userinfo, and JWKS from it automatically:
https://login.microsoftonline.com/<tenant-guid>/v2.0/.well-known/openid-configuration
Open it in a browser to confirm it returns JSON.
2. Network ACL — check before you assume you need it
Social Sign-In makes outbound calls from the database to Microsoft, so the parsing schema must be allowed to reach the Microsoft endpoints. On our Always Free ATP instance this was already in place — we did not have to make any ACL change, and login worked without touching DBMS_NETWORK_ACL_ADMIN. Your instance may differ depending on its network egress configuration, so test login first and only add an ACL if it fails.
The symptom that tells you an ACL is missing: login dies with ORA-24247 network access denied. If you hit that, grant the parsing schema connect privilege to login.microsoftonline.com and graph.microsoft.com. On Autonomous Database, appending to the ACL is done as ADMIN, and the exact call varies by release — verify against current Oracle docs before running it.
Then raise the web-service request limit: INTERNAL workspace → Manage Instance → Security → Workspace Isolation → Maximum Web Service Requests.
3. APEX Web Credential
In App Builder → Workspace Utilities → Web Credentials, click Create:
| Field | Value |
|---|---|
| Name | Azure OIDC |
| Authentication Type | OAuth2 Client Credentials Flow |
| Client ID or Username | Application (client) ID |
| Client Secret or Password | Secret Value |
| Valid for URLs | https://login.microsoftonline.com |
The secret is stored encrypted. Note that updating “Valid for URLs” later forces you to re-enter the secret.
4. Social Sign-In Scheme
Open the app → Shared Components → Authentication Schemes → Create → Based on a pre-configured scheme from the gallery, Scheme Type Social Sign-In:
| Field | Value |
|---|---|
| Name | Azure AD OIDC |
| Credential Store | Azure OIDC |
| Authentication Provider | OpenID Connect Provider |
| Discovery URL | .../v2.0/.well-known/openid-configuration |
| Scope | openid email profile |
| Username Attribute | preferred_username |
| Convert Username To Upper Case | Yes (if roles are stored uppercase) |
| Verify Attributes | Yes |
Set Username to #preferred_username#. This is the single most important field on the page, and the reason is in the Gotchas below.
5. Activate safely (don’t lock yourself out)
Making a scheme Current routes all app login through Entra. If it’s misconfigured you cannot fall back from the runtime app. Do it in this order:
- Keep your App Builder session open in the current browser — that is your revert path.
- Make Azure AD OIDC the Current scheme.
- In a separate incognito window, open the app home URL.
- Expected: redirect to Microsoft → authenticate → first-time consent → redirect back, logged in.
- If it fails, return to the still-open App Builder session and set the scheme back to Oracle APEX Accounts.
6. Authorization — open entry, role-gate the rest
Authentication (who the user is) is Entra’s job; authorization (what they may do) is Application Access Control, and the two are independent.
Layer 1 — app entry. In Shared Components → Application Access Control → Configure Access Control, set “Any authenticated user may access this application” to Yes. Any successfully authenticated user can open the app without being listed — this removes the “Access denied by Application security check” wall.

Layer 2 — privileged pages. Define roles (e.g. ADMINISTRATOR, CONTRIBUTOR, READER). APEX auto-creates a matching Authorization Scheme per role; attach it to the page, region, button, or process you want to gate, and grant the role only to the few users who need it. Everyone else gets the default read-only experience.
This avoids per-login role provisioning: most users need no role at all, only elevated users get one, and the access list stays small and meaningful.
Alternative: broker through an OCI Identity Domain
Instead of APEX speaking OIDC directly to Entra, APEX can speak OIDC to an OCI Identity Domain, which federates authentication to Entra via SAML. The user still signs in at Azure; APEX only ever speaks OIDC to OCI. We proved this variant alongside the direct path, for the case where one identity hub should front multiple IdPs or where the same domain already fronts the customer’s Fusion pod.
Create a Confidential Application in the domain (OCI Console → Identity & Security → Domains → Integrated applications → Add application), grant type Authorization Code, Redirect URL = the same APEX callback. Activate it, copy its Client ID and Client Secret, and note its discovery URL:
https://<domain-id>.identity.oraclecloud.com/.well-known/openid-configuration
In APEX, build a second Web Credential (OCI OIDC) and Social Sign-In scheme against that discovery URL. Two differences from the direct path matter, both found during testing — see Gotchas.
Gotchas / Production notes
- Use
preferred_username, neveremail, as the Username Attribute (direct Entra path). Entra users without a mailbox have noemailclaim, which produces “Null username passed to login procedure” for exactly those users.preferred_username(the UPN) is populated for every user. Don’t use#sub#either — it’s an opaque GUID that won’t match your ACL grants. - Guest/external users surface as
user_domain.com#EXT#@tenant.onmicrosoft.com. That UPN is the value the token returns, so any role grants must use that exact string. - On the brokered OCI path, use
#sub#instead. IDCS-style OCI domains advertise only a minimal base claim set (aud, exp, iat, iss, jti, sub) — no guaranteedpreferred_username/emailin discovery — so#sub#is the safe choice. Confirm what#sub#resolves to on first login and key your role grants to that. - Brokered path: do NOT put
openidin the Scope field. APEX addsopenidautomatically. If you also set it, the request sendsopenid openid profile emailand the domain rejects it withinvalid_request/ “duplicate values.” Set Scope toprofile emailand let APEX addopenid. (Hit and resolved during testing.) - No local APEX account is needed. Don’t create accounts via
APEX_UTIL.CREATE_USER. With Social Sign-In the IdP authenticates the user; we confirmed login still works after deleting the local account. AADSTS50011redirect_uri mismatch means the URI APEX sent isn’t registered. Copy the exact URI from the Microsoft error page into App Registration → Authentication → Redirect URIs verbatim.- Entra secrets expire and take all logins down with them. When the secret lapses every login fails at the token step (
invalid_client/AADSTS7000215). Rotate before expiry — see below.
Client-secret rotation (zero downtime)
Entra allows two valid secrets on one registration at once, so rotation is outage-free:
- Create a new secret in Entra (new expiry, copy the Value immediately).
- Paste it into the APEX Azure OIDC Web Credential (Client Secret + Verify), Apply. The Client ID is unchanged.
- Test in an incognito window.
- Delete the old secret in Entra so a leaked old value can’t be used.
- Record the new expiry and set a reminder 2–4 weeks ahead.
The brokered OCI path generally avoids this clock: the secret APEX holds is the OCI confidential-app secret, which is usually long-lived. Confirm its expiry in your OCI Console rather than assuming — whatever you find there determines whether forced rotation applies to this path at all.
How to verify
- Login round-trip: in incognito, open the app home URL; you should bounce to Microsoft, authenticate, and land back inside the app.
ORA-24247 network access deniedat login → the parsing schema can’t reach the Microsoft endpoints; add the ACL (Section 2). On our Always Free instance this wasn’t needed, but yours may require it.Access denied by Application security check→ authentication succeeded, authorization didn’t. Either set “Any authenticated user may access” = Yes, or grant the user a role.- Username is a GUID or blank → Username Attribute is set to
subor the wrong claim on the direct path; switch topreferred_username. - All logins fail at the token step → expired/wrong client secret; rotate.
Conclusion
OIDC Social Sign-In gives an APEX app on managed ATP real corporate SSO without taking over ORDS and without provisioning a single local account. Entra owns identity, Application Access Control owns authorization, and onboarding a new user becomes a no-op. The brokered OCI variant adds an identity hub when you need to federate several IdPs or share one source with Fusion.
Get this into your environment
Facing the SAML-on-managed-ORDS wall, or wiring an APEX app to Entra and unsure whether to go direct or broker through OCI? We’ve built and proven both patterns end to end, and we can implement them in your environment. Reach out at info@cidsolutions.co.il or WhatsApp — let’s get it solved.
Tags: Oracle APEX, Autonomous Database, ATP, OIDC, Microsoft Entra ID, Azure AD, Single Sign-On, ORDS, OCI Identity Domain, Social Sign-In
Related posts: (first APEX post — no prior chain link yet. Forward-links to add as the APEX chain grows: OAuth setup for REST Data Sources, and REST Data Source Synchronization caching.)