QSDA study materials
QSDA study resources

Region-Level Security in a 2,400-User Published App

QSDA · Put your knowledge to work in context.

All case studies

Region-Level Security in a 2,400-User Published App

A global manufacturer publishes one Qlik Sense app to 2,400 users across 14 sales regions. A Region field exists in the sales fact. Requirements: regional managers see only their own region, 30 head-office users see everything, and the service account that reloads must be able to reload without anyone seeing data they should not. The current script has an INLINE section access table with 2,400 USERID rows, ACCESS\ADMIN on each, and REDUCE on Region. Symptoms after the last change: one region manager sees all 14 regions, another sees a blank app with no error, and the nightly reload started failing.

1. Diagnose each of the three symptoms. State the likely cause and the check you would run to confirm it.

Read the worked answer

Manager sees all 14 regions. Most likely ACCESS\ADMIN in the table - ADMIN bypasses data reduction entirely, and 2,400 ADMIN rows means nobody is actually being reduced. Confirm by querying the section access table for distinct ACCESS values; any ADMIN outside a named head-office group is a defect. Second candidate: a row where the Region value is blank or a wildcard (*), which matches everything for whoever resolves to it in the ordering of rows.

Blank app, no error. The reduction field value in section access does not match the model value. Usual culprits: case or trailing whitespace (north vs North), the field being renamed or dropped downstream by a preceding load or a join, or a user resolving only to rows that do not exist in the data. Confirm by loading the app as that user in a test environment, and by comparing SELECT DISTINCT Region from the source against SELECT DISTINCT Region from the section access table - two lists, diffed, is the whole check.

Reload failing. Every account that opens or reloads the app must be present in section access, including the Qlik service account and any reload/scheduler identity, either explicitly or via a wildcard group row. That account was almost certainly dropped in the last change. Confirm from the task execution log's identity, then verify a matching row exists.

Test every fix in a dev app with a test USERID and strict exclusion relaxed, never in the published app.

2. A colleague suggests replacing REDUCE on Region with OMIT so the field is hidden. Explain the difference and why OMIT does not meet the requirement.

Read the worked answer

They solve different problems.

REDUCE removes rows from the data model for the user - a regional manager's app contains only their region's transactions. The field stays, associations stay, the totals are correct for what they can see, and anything they compute is derived only from permitted rows.

OMIT leaves every row in the model and only stops the field from being displayed or selectable. The user still has all 14 regions' data behind the scenes; they just cannot see or filter on the Region column. Every total on every sheet still includes other regions' amounts. It is a display control, not an access control.

So OMIT on Region would give the regional manager a dashboard that silently adds up the whole world, which is worse than a visible leak because it looks plausible.

Where OMIT is legitimate: hiding the reduction field itself from the user interface after REDUCE has done the work, or hiding a sensitive column (margin, salary) that no sheet needs. That is presentation, and it must sit alongside row-level reduction, never instead of it.

Also worth stating: neither mechanism replaces the discipline of checking that every downstream load keeps the field named exactly as section access expects. A rename after section access is loaded breaks the link just as effectively as omitting it.

3. How would you govern this security table going forward so the next change does not repeat the incident?

Read the worked answer

Move it out of the script. 2,400 rows inline in a Qlik script is a change-controlled text file pretending to be a database. Put the mapping in a source-controlled table or a QVD written by the security team's own job, and let the app read it. The app then has no reason to be edited when someone joins or leaves.

Own the field, not just the values. Security owns the mapping; the data team owns the fact. Both must agree on one canonical Region list. The failure mode is always drift - a new region code in the ERP that nobody added to the mapping, producing blank apps and support tickets.

Automate the checks. Before publishing: diff the distinct Region values in the fact against the mapping and fail the reload on any unmatched value. Then a small test-fixture app with one USERID per region plus a wildcard row, reloaded on every change, so a regression is caught before a user finds it.

Keep the reduction rules auditable. Store who approved each mapping change, keep the previous version, and record the section access load in the app's reload log so you can answer 'who could see what, in March' without rebuilding anything.

Least privilege. Head-office access via a named group row rather than 30 individual rows, no ADMIN except for a documented, tested admin identity, and the reload service account granted the minimum that lets it reload rather than full data visibility where that is avoidable.