Umbra
← All docs

Module access & entitlements

Two layers of module gating: per-org bundle entitlement (what the plan sells) and per-user module grants (an org-admin restricts a teammate to specific modules). Allow-by-default, dependency-closed, server-enforced, fails closed.

Last updated Aug 23, 2026

What it is

Beyond the four-role ladder, Umbra gates access at the module level in two independent layers:

  • Per-org bundle entitlement: the set of modules a workspace is allowed to use at all. It’s what the plan sells (Deep Audit unlocks at Starter, Cloud at Pro, Internal Pentest at Business, etc.), and a super-admin can override it per org (grant a bundle a plan wouldn’t normally include, or carve one out for a bespoke deal).
  • Per-user module grants: inside an entitled org, an org_admin can restrict an individual teammate to specific modules. Grants are allow-by-default: a user sees every module the org is entitled to unless an admin explicitly denies one for them.

Both layers are server-enforced. They aren’t UI hints. The API checks them on every request and fails closed if any layer says no.

How the layers compose

Effective access to a module is the intersection of three checks, evaluated on every request:

  1. Role band: viewer / member / admin / owner (see Roles + audit log). The role decides what kind of action is allowed (read vs. mutate vs. administer).
  2. Per-org bundle entitlement: is this module part of the workspace’s bundle at all? Set by the plan; super-admin can override per org.
  3. Per-user module grants: has an org_admin denied this specific module for this specific user? Allow-by-default, so the answer is “yes” unless someone turned it off.

A request is permitted only when all three permit it. If the org isn’t entitled, nobody in it gets the module regardless of role; if a user is denied a module, their role doesn’t buy it back.

Dependency closure

Modules aren’t fully independent. Some depend on others to function. Entitlements and grants are resolved with dependency closure: granting (or denying) a module pulls in the modules it requires so you never end up with a half-wired capability that’s visible but can’t run. Deny a prerequisite and the dependents it feeds are unavailable too; entitle a module and its prerequisites come along.

What it produces

  • A per-org entitlement set: the modules the workspace may use, derived from its plan bundle plus any super-admin override.
  • A per-user grant/deny map: the modules an org_admin has narrowed for a given teammate (empty = full org access, the default).
  • A single server-side decision per request: allowed / denied with the layer that made the call, so denials are consistent across the API, the dashboard, and background jobs.

What to use it for

  • Least privilege for teammates. Give a contractor “only Deep Audit” without also handing them Cloud posture, Internal Pentest, or billing.
  • Plan-accurate feature gating. The org only sees what its plan sells; upgrades light up modules without a redeploy.
  • Bespoke deals. Super-admin grants a specific bundle to a specific org (e.g. a Pro customer piloting Internal Pentest) without changing the published plan matrix.
  • Separation of duties. One teammate runs audits, another only reviews cloud findings. Enforced, not just agreed.

Why it matters

”Granular access” is the line item enterprise buyers actually check. A role model alone can’t answer “can this contractor be locked to one module?” That needs module-level gating, and it has to hold at the server, not the UI, or it isn’t a control. Umbra’s per-org + per-user split is the differentiator that makes per-target grants and per-user module access a real, demonstrable capability rather than a checkbox.

Why it’s valuable

  • Two clean layers. Org entitlement answers “does the plan include it”; per-user grants answer “should this person have it”. No tangled single matrix.
  • Allow-by-default. Teams aren’t forced to hand-grant every module to every user; you only spend effort where you need a restriction.
  • Fails closed. Ambiguity resolves to “denied,” so a misconfiguration under-exposes rather than leaking a module.
  • Dependency-aware. You can’t accidentally strand a module by denying something it needs. Closure keeps the set coherent.

How to use it

  • Per-org bundle is set by the plan automatically; super-admin (Umbra staff) applies per-org overrides on request.
  • Settings → Team → (a member) → Module access for an org_admin to deny specific modules for that teammate. Everything not denied stays available (within the org’s entitlement).
  • Verify a restriction by signing in as the teammate (or using an impersonation-safe test account): denied modules don’t render and their API routes return a not-entitled error.

Related: