Skip to content
Menu

Access control

View .md

Beacon’s access model has four layers. Set each one deliberately before people start using it.

flowchart TB
  R["Global role<br/>Admin · Editor · Viewer<br/><i>the ceiling</i>"] --> P["Project membership<br/>ProjectAdmin · Editor · Viewer<br/><i>what you can touch</i>"]
  P --> A["Project action<br/>Read · Run · Query · Write · Manage · ManageMembers · Curate"]
  F["Functional permissions<br/>Approver · Auditor · SecurityAdmin<br/>UserAdmin · DataSourceAdmin · MigrationOperator<br/><i>duties, no data</i>"] -.-> X["Admin screens and decisions"]
  L["Deployment locks<br/>config only, bind Admins too"] -.-> A

Every user has at most one global role, which caps everything else:

RoleCan
ViewerRead, and run existing checks, in projects they can reach.
EditorAlso create and change queries, subscriptions and other project content.
AdminEverything, in every project, plus every functional permission.

The first super admin is created at first-run setup. Give Admin to as few people as possible. The functional permissions below exist so that most administrative duties do not need it.

A project groups data sources and the queries, subscriptions, contracts and grounding built on them. Access is decided per project by one component, IProjectAccessEvaluator:

  • Restricted projects are visible only to their members and to Admins. Everyone else gets 404, so the existence of the project is not disclosed.
  • Open projects are visible to everyone with a global role, at that role.
  • New projects start restricted, with their creator as ProjectAdmin.
  • A data source follows the projects that link it. Something that reads several data sources is reachable only through one project that links all of them. Data sources created after project access was introduced are Admin-only until linked to a project.
Project roleActions
ViewerRead, Run
Editor+ Query (ad-hoc SQL, MCP queries), Write; + Manage in open projects
ProjectAdmin+ Manage, ManageMembers, Curate (review learned patterns, documentation and relationships)

A global Viewer is a Viewer in every project, whatever their membership; Editors and Admins act with their membership role (and in an open project, with the higher of that and their global role). ManageMembers and Curate come only from a ProjectAdmin membership and are never granted to API keys, MCP callers or scheduled work.

Make every project restricted with Beacon:Authorization:RequireProjectMembership: true. Startup then requires a membership source (Beacon’s user store, or your IProjectMembershipSource).

Plan the first projects before inviting users:

  1. Create one project per team or data domain.
  2. Link each data source to the projects that should see it.
  3. Add members with the lowest role that works.

Administrative duties are split out of the Admin role. Each is held through a functional role of the same name (a system role with no data access), assigned by an Admin, or mapped from an identity-provider app role at SSO sign-in.

PermissionGrants
ApproverApprove or reject query changes and change requests (migration jobs, Custom SQL rules, recipient destinations).
AuditorRead and verify the security audit trail; read the MCP audit log, MCP settings, admin settings, every API key and what a user owns, created or changed last.
SecurityAdminChange MCP and admin settings (not the LLM connection or base URL, which are Admin only), manage notification recipients, publish saved queries as MCP tools, set repository tokens.
UserAdminManage users and their non-privileged roles, end sessions, see what a user owns, created or changed last, revoke API keys, change owners of scheduled work, manage project members, restrict projects.
DataSourceAdminCreate, test and delete data sources; link them to projects they can read.
MigrationOperatorCreate and run data-migration jobs (only when migrations are enabled).

A functional permission grants no project data. A UserAdmin can never grant Admin or a functional role, nor touch Admins or other privileged users. API keys never hold a functional permission.

{
"Beacon": {
"Authorization": {
"RequireProjectMembership": true,
"Roles": { "Approver": "Beacon Approver" },
"IdpRoles": {
"Enabled": true,
"Map": {
"Beacon.Auditor": "Auditor",
"Beacon.SecurityAdmin": "SecurityAdmin"
},
"ClaimLifetimeMinutes": 60
},
"SeparationOfDuties": { "Enabled": true }
}
}
}
KeyDefaultWhat it does
Roles:{Permission}the permission’s nameRename the functional role that grants a permission (not Admin/Editor/Viewer; unique).
Roles:HonourHostRoleClaimsfalseWithout Beacon’s user store: let a role claim named like a functional role grant the permission.
IdpRoles:Enabled / MapoffMap identity-provider app roles to permissions at SSO sign-in. Mapped permissions live in the session only and are not stored.
IdpRoles:ClaimLifetimeMinutes60How long a mapped permission counts after sign-in.
SeparationOfDuties:EnabledfalseRefuse giving one person both halves of a conflicting pair: Approver + SecurityAdmin, Auditor + SecurityAdmin, Auditor + UserAdmin, UserAdmin + Approver, UserAdmin + MigrationOperator.

Opt in with options.EnableApprovalWorkflow(...). Then a change to a query’s executable content goes live only after a second person with the Approver permission approves exactly the content they reviewed, and scheduled runs execute only reviewed SQL. By default it also covers migration jobs, Custom SQL rules and new or changed notification destinations.

options.EnableApprovalWorkflow(x =>
{
x.RequireApprovedVersionToRun = true; // strict: run only versions with an approval for their exact content
// x.AllowSelfApproval = true; // only for a deployment with a single possible approver
// x.CoversMigrationJobs = false; // per-kind switches, all true by default
});

Make sure at least two people hold Approver (Admins count). Full rules: Approvals.

Some guarantees should not depend on an individual Admin’s actions. These keys can only be changed in host configuration. The UI shows the setting disabled, and the API answers 409:

KeyDefaultPins
Beacon:Mcp:ForceReadOnlytrueRead-only SQL everywhere the gate runs.
Beacon:Mcp:ForcePiiDetectiontruePII detection and masking on.
Beacon:Mcp:ForceNoContentRetentionfalseNo question, SQL or error text stored with MCP audit rows.
Beacon:Mcp:ForbidRowDataToLlmfalseNo row values (samples, value grounding, eval judging) sent to the LLM provider.
Beacon:Mcp:Audit:RequireContentfalseContent retention on: MCP audit rows keep the question and the SQL of every statement a call ran. Cannot be combined with ForceNoContentRetention.
Beacon:Mcp:Ceilings:MaxRowLimitnoneUpper bound for every project’s MCP row limit.
Beacon:Migrations:EnabledfalseThe only write path. Off: no migration endpoints, no jobs, for anyone.

See Security model for how these fit together, and Authorization for the full reference.

For a typical company deployment:

  • RequireProjectMembership: true
  • SSO with AllowedTenants, RequiredGroups, RequireMfa; local login off with one break-glass account
  • Two or more Approvers, one Auditor, one SecurityAdmin; SeparationOfDuties on
  • Approval workflow on, with RequireApprovedVersionToRun
  • Locks left at their defaults; ForbidRowDataToLlm on if row values must never reach your LLM provider
  • Migrations off unless you need them
  • Beacon:Audit:IntegrityKey set from a secret store, and the security audit verification and retention jobs scheduled