← Back to blog

Oracle Fusion REST API Authentication: Basic Auth, JWT, and OAuth 2.0

By Mostafa Mansour 10 min read Oracle FusionREST APIAuthenticationOAuthJWTSecurity

Every Oracle Fusion REST API call — HCM, Financials, or SCM — starts with the same question: how do I authenticate? Oracle supports three mechanisms, and picking the wrong one for your scenario is the most common reason integrations stall in week one. This guide covers all three with working examples, and ends with the 401-vs-403 troubleshooting table that resolves most “authentication” tickets (spoiler: half of them are authorization problems, not authentication).

All examples use an anonymized pod (acme.fa.us2.oraclecloud.com) and placeholder users ([email protected]). Swap in your own hostname and credentials.

The three options at a glance

MethodBest forSetup effortToken expiry
Basic Auth over TLSDevelopment, testing, quick internal scriptsNoneN/A (credentials sent per request)
JWT bearer (trusted issuer)Server-to-server integrations you controlMedium — upload signing certificate onceYou set it in the token (keep it short)
OAuth 2.0 via IDCS/IAMProduction integrations, third-party apps, user-context flowsHighest — register a confidential appManaged by the identity domain

One rule that surprises people: Fusion authorization is always user-based. Whatever method you choose, the token or credential resolves to a Fusion user, and that user’s roles decide what the request can touch. There is no “app-only” access to business data — server-to-server flows run as a dedicated integration user.

Basic Auth over TLS

The simplest option and completely fine for development. Credentials travel base64-encoded in the Authorization header on every request, so TLS is mandatory (Fusion pods only serve HTTPS anyway).

curl -u '[email protected]:YourPassword' \
  'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers?limit=5'

Or with an explicit header:

GET /hcmRestApi/resources/11.13.18.05/workers?limit=5
Authorization: Basic aW50ZWdyYXRpb24udXNlckBleGFtcGxlLmNvbTpZb3VyUGFzc3dvcmQ=

Drawbacks for production: passwords expire on the pod’s rotation policy (integrations break silently at 3 a.m.), credentials are replayable if leaked, and there is no scoping — the header is the full identity. Oracle’s own guidance is to move to OAuth 2.0 for anything long-lived.

JWT bearer with a trusted issuer

The middle path: your system signs a JWT with a private key, Fusion validates it against a certificate you uploaded once. No identity-domain round trip per request, no password rotation problem.

One-time setup in Fusion (Security Console → API Authentication):

  1. Generate a key pair and an X.509 certificate for your issuer.
  2. Create a JWT Issuer entry with your issuer name and upload the certificate.
  3. Ensure the integration user exists in Fusion with the roles the integration needs.

Your system then builds a JWT per call (or per short session):

{
  "alg": "RS256", "typ": "JWT", "x5t": "<cert thumbprint>"
}
{
  "iss": "www.example.com",
  "prn": "[email protected]",
  "sub": "[email protected]",
  "iat": 1780000000,
  "exp": 1780000900
}

Sign it with your private key and send it as a bearer token:

curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  'https://acme.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/invoices?limit=5'

The prn/sub claim must match an active Fusion username — that user’s roles are what the request runs with. Keep exp short (15 minutes is common); the token is self-contained, so a leaked one is valid until expiry.

OAuth 2.0 via IDCS / IAM identity domain

The production-grade option, and required when a third party (or Entra ID federation) is involved. Your Fusion instance has an associated Oracle identity domain (IDCS, or OCI IAM on newer tenancies) that issues tokens.

One-time setup in the identity domain console:

  1. Register a confidential application.
  2. Enable the grant types you need (client credentials + JWT user assertion for server-to-server; authorization code for user-facing apps).
  3. Add the Fusion application resource scope to the app.
  4. Note the client ID and secret.

Because Fusion needs a user context, pure client-credentials tokens are not enough for business-object APIs — server-to-server flows use the user assertion variant: your app authenticates with its client credentials and asserts which Fusion user the token should represent.

Token request:

curl -u '<client_id>:<client_secret>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
  --data-urlencode 'assertion=<signed user-assertion JWT>' \
  --data-urlencode 'scope=<fusion app scope>' \
  'https://idcs-abc123.identity.oraclecloud.com/oauth2/v1/token'

Then use the returned token exactly like the JWT above:

curl -H "Authorization: Bearer <access_token>" \
  'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers?limit=5'

The win over trusted-issuer JWT: central revocation, audit, token lifetime policy, and rotation all live in the identity domain instead of your code.

Fusion’s own identity domain vs. an external one: the certificate decision that adds days, not minutes

Step 1 above (“register a confidential application”) hides a real fork in the road: which identity domain you register it in changes how long setup takes.

Register directly in Fusion’s own Applications Identity Domain — the identity domain that ships pre-integrated with your Fusion instance — and there’s no certificate or trust step. Create the confidential application there, add the Fusion resource scope, note the client ID/secret, and you’re done same-day.

Register in a separate, external identity domain instead — a standalone OIC identity domain, or a “Default” IDCS/IAM domain your org already uses for other apps — and Fusion has to be told to trust it before it will honor tokens that domain issues. That trust isn’t self-service: you raise a Service Request with Oracle Support, share the external domain’s signing certificate, and wait for Oracle to attach it to your SaaS instance’s API Authentication Provider in the Security Console. Budget real lead time for the SR round-trip, not just an extra checkbox — this is the step that most often turns a same-day OAuth setup into a multi-day one.

Unless something else in your architecture already centralizes OAuth apps elsewhere — the most common reason is Oracle Integration Cloud, where all your OIC connections share one identity domain by design — register directly in Fusion’s own identity domain and skip the SR.

Redirect URI only matters for user-facing flows. The client-credentials/user-assertion pattern above is server-to-server with no browser involved, so the app needs no redirect URI at all. If you’re setting up the Authorization Code flow instead — a user-facing app, or just testing token retrieval manually in Postman — the confidential application needs a redirect URI configured: an OIC connection’s own callback URL, or Postman’s callback URL (https://oauth.pstmn.io/v1/callback) when you’re testing by hand.

401 vs 403 — authentication vs authorization

The single most useful distinction when debugging:

StatusMeaningUsual causes
401 UnauthorizedFusion doesn’t know who you areWrong password, expired token, clock skew on iat/exp, issuer certificate not uploaded, malformed Authorization header
403 ForbiddenFusion knows who you are and says noIntegration user missing the duty/job role for that resource, data security (the user’s role sees no rows in that business unit or legal entity)
404 on a real endpointSometimes authorization in disguiseA few resources return 404 rather than 403 when the user has no access — check roles before doubting the URL

If you get a 401 with Basic Auth that worked yesterday, check password expiry first. If you get a 403 on /workers but 200 on /locations, the user is fine — the role is missing. Role setup happens in the Security Console, not in the API. If an OAuth-authenticated integration was working for hours and then started throwing 401s with no code change, that’s almost always an expired access token, not a broken credential — see our OAuth token expiration and refresh guide for the refresh_token flow and the two errors that trip up most retry logic.

403 Forbidden: it works in the Fusion UI, but not through REST

This is the single most common authentication ticket that isn’t actually about authentication. A user can open the exact record in the Fusion UI, but the identical call through REST comes back 403 — several real, recurring threads on Cloud Customer Connect ask this near-verbatim (“403 forbidden error from /erpintegrations fusion rest api, seeking to know required privilege”; “Getting 403 forbidden error while calling Fusion Rest api, How to solve this issue?”), and it’s the subject of at least four separate Oracle Support knowledge articles. The confusion is understandable: REST and the UI are secured by the same underlying model, but the two layers of that model fail differently.

Job/duty role — can this user call this operation at all. This is function security: a predefined or custom job role has to include the aggregate privilege for the specific REST resource and HTTP method. Missing this, and every request against that resource returns 403 immediately, GET included.

Data role — which records this user’s role is scoped to see. This is data security: the same job role, assigned through a data role, is scoped to one or more business units, legal entities, or (in HCM) a person security profile. A user can have full function access to /invoices and still get 403 — or a 200 with zero rows, which is easy to mistake for “the record doesn’t exist” — if their data role doesn’t cover the business unit the record lives in.

The reason this trips people up specifically on REST and not the UI: Fusion’s Security Console UI is often set up and tested against a named individual’s full access, while integration users are provisioned narrowly (correctly, per the least-privilege guidance above) and it’s easy to grant the job role while forgetting the matching data role scope. A smaller number of tenants also apply Location-Based Access Control, which can restrict REST clients by network/IP independently of what a browser session is allowed — worth ruling out if the same integration user works fine from one network and not another.

To diagnose: in the Security Console, open the integration user and confirm the required job/duty role is (a) assigned directly and (b) included in a data role whose business unit, legal entity, or person security profile actually covers the record you’re calling. If the job role is present but scoped too narrowly, you’ll typically see 403 on writes and either 403 or a clean empty result set on reads — both point the same direction. This is also why the Oracle HCM API guide calls out that a bare OAuth 2.0 Client Credentials token can’t carry this context at all: HCM’s row-level data security needs a resolvable Fusion user behind the token, not just a valid app credential.

Which method should you use?

Whatever you pick, create a dedicated integration user with the minimum roles the integration needs — never run integrations as a personal account, and never grant an integration user broad roles to “make the 403s go away.”

Testing authenticated requests faster

Once auth works, the slow part becomes figuring out what to call — which of the 59,000+ endpoints, which q fields, which finders. OPAL bundles the full HCM and FSCM catalogs offline in a searchable endpoint reference, stores your credentials locally encrypted (AES-256-GCM, no cloud), and sends live authenticated requests — Basic or token — without you hand-writing headers. The HCM examples post shows what those requests look like end to end, and the Oracle HCM API guide covers the HCM-side setup in more depth.


This post is part of our complete Oracle Fusion API guide — pillars, base URLs, authentication, q filters, finders, and common errors in one place.

Explore Oracle Fusion APIs offline

OPAL bundles 59,000+ Oracle Fusion REST endpoints, fully searchable offline, with a visual Q Builder and Finder Builder that only offer fields the endpoint actually accepts — so your filter can't 400.

Free, no account required. Pro adds live requests and multi-step Flows.