All posts · BI Reports

BI Publisher Security: Row-Level Access and User Permissions

Controlling who can see what in BIP reports — data security via SQL parameters, report-level access, and role-based catalog permissions.

Anurag Jangra · February 26, 2026 · 5 min read · ... views

Security layers in BI Publisher

BIP has multiple independent security layers:

  1. Catalog permissions: who can open, edit, or delete reports
  2. Data security: what data a user sees when they run a report
  3. Delivery security: what delivery channels and addresses a user can specify
  4. Oracle Fusion data roles: Fusion restricts which subject areas and data an OTBI user can access

Catalog permissions

BIP catalog objects have individual permission settings:

  • Open: can run the report
  • Read: can view but not run
  • Write: can edit the report
  • Delete: can delete

Assign to users, roles, or groups. Best practice: create a BIP report viewer role, grant Open permission to all production reports, and add users to the role rather than managing individual permissions.

Row-level security via SQL

The most important security mechanism: filter data in the data model SQL based on the logged-in user:

SELECT po.*, s.supplier_name
FROM po_headers po
JOIN suppliers s ON po.supplier_id = s.supplier_id
WHERE po.requester_id = :xdo_user_id  -- BIP's current user parameter
  AND po.org_id IN (
    SELECT org_id FROM user_org_access WHERE username = :xdo_user_name
  )

:xdo_user_id and :xdo_user_name are BIP built-in parameters containing the authenticated user’s details.

Business unit and ledger security

For Finance reports, use Fusion’s data role hierarchy to determine which ledgers/BUs a user can see:

WHERE gl.ledger_id IN (
  SELECT ledger_id FROM fusion_gl_access_sets
  WHERE user_id = :xdo_user_id
)

Never rely solely on UI-level access control — always enforce at the SQL level.

Sensitive data masking

For reports distributed outside the organisation or to non-privileged roles, mask sensitive fields in the data model:

SELECT
  employee_id,
  last_name,
  REGEXP_REPLACE(national_id, '.{4}$', 'XXXX') AS masked_national_id,
  REGEXP_REPLACE(bank_account, '[0-9]', 'X', 1, 0) AS masked_account
FROM employees

Audit trail

Log all report executions for compliance:

INSERT INTO report_access_log (user_id, report_name, parameters, run_dt)
VALUES (:xdo_user_id, 'PO_Detail_Report', :P_PARAMS, SYSDATE);

Use autonomous transactions so the log persists even if the report fails.

Think Beyond the Implementation

Questions worth sitting with after reading this

01

Why is this architecture appropriate for this specific context — and where would it be the wrong choice?

02

What assumptions did we make that aren't stated explicitly? What happens if those assumptions are wrong?

03

What would break first if the requirements changed — volume doubled, a third system was added, or the deadline halved?

04

What alternatives did we reject, and why? Was the decision made on evidence — or habit?

AJ
Anurag Jangra
Oracle Cloud PaaS Consultant · OIC & VBCS Specialist

4.5+ years delivering enterprise Oracle Cloud integrations and VBCS applications across manufacturing, IT services, and financial sectors. OCI Certified — writes about real-world OIC, VBCS, SQL, and BI Publisher patterns from production experience.

Chat on WhatsApp