Documentation

Users, roles & organizations.

Organizations & quotas

What it is. Multi-tenancy. A single AccessFlow deployment hosts one or more organizations, each a fully-isolated tenant — every user, datasource, query, and audit row belongs to exactly one org, and a tenant can never reach another's data. Reach for it when you host several teams or customers on one deployment and want per-tenant resource caps; most operators run a single org and can ignore the cross-org controls.

Platform admin (super-admin). Managing organizations across the cluster requires the platform-admin capability — a flag on a user, separate from the four roles below. A platform admin keeps their normal org role and additionally sees a Platform navigation group with the /admin/organizations screen. The first admin you create (via the setup wizard or the bootstrap env vars) is provisioned as a platform admin automatically.

The AccessFlow platform-admin Organizations page listing each tenant organization with its per-org datasource, user, and daily-query quotas.
/admin/organizations — platform admins manage every tenant and its quotas from one screen.

Configure it. Platform admins manage tenants and their quotas from /admin/organizations:

  1. Create an organization. From /admin/organizations, click New organization, give it a name (an optional URL-safe slug is derived from the name when blank), and optionally set quotas. The org starts enabled and empty — add its first admin and datasources afterwards.
  2. Set per-org quotas. Cap how much a tenant may consume: max datasources, max users, and max queries per day (a rolling trailing-24-hour count). Leave a field blank or set it to 0 for unlimited. Quotas are enforced when the resource is created — a breach is rejected with HTTP 409 QUOTA_EXCEEDED and a message naming the limit, so the datasource / user / query simply isn't created.
  3. Edit name & quotas. Open /admin/organizations/<id> to change the name or raise / lower a quota, and to see live usage bars (current count vs. limit) for each cap.
  4. Disable a tenant. Use Disable as a kill-switch — its users are blocked at login (local and SSO) and every in-flight session stops on its next request. The block is immediate (no cache, no waiting for token expiry). Enable restores access.

Every organization action (create, update, disable, enable) is written to the audit log against the target org. Per-org login pages / SSO routing across multiple orgs are not yet available — see the roadmap.

Languages & localization

What it is. AccessFlow ships seven bundled interface languages — English, Español, Deutsch, Français, 简体中文, Русский, and Հայերեն. An org admin decides which of them users may choose, which one users start on, and which language the AI reviewer writes in.

Configure it. /admin/languages (admin-only) has three controls: an available languages checklist (at least one required) that drives the language switcher in the top bar; a default language select, narrowed to that allow-list, applied to users who have not picked one; and an AI review language select spanning all seven languages independently of the user allow-list. Saving refreshes the top-bar switcher immediately.

Tune it. Users override the default themselves from the language switcher next to the theme toggle, and the choice persists to their profile. Any string missing from a translation falls back to English.

Users

What it is. The people who can sign in to AccessFlow and the role each one carries. Create accounts directly, or let SAML / OAuth users be auto-provisioned on first sign-in when SSO is enabled (see SAML and OAuth).

Configure it. Manage everyone from /admin/users:

Invite a teammate modal in the AccessFlow admin Users page, with fields for email, display name, and a role dropdown defaulting to ANALYST.
/admin/usersInvite via email. Enter the recipient's email, pick a role, and AccessFlow emails a one-time signup link.
  1. Invite via email (default). From /admin/users, click Invite via email, fill in the recipient's email, optional display name, and role, then submit. AccessFlow generates a signup token and emails it; the link expires after ACCESSFLOW_SECURITY_INVITATION_TTL (default 7 days).
  2. Create with a password. Use the dropdown next to the invite button → Create with password to provision a user directly. Useful when SMTP isn't configured yet, or when you want to seed an account synchronously.
  3. Edit or deactivate. Click any row to change the role or flip the active toggle. Deactivated users can't sign in but their audit trail is preserved.
  4. Pending invitations are listed below the user table; resend or revoke them from there.

Tune it. ACCESSFLOW_SECURITY_INVITATION_TTL (invite-link lifetime, default P7D), ACCESSFLOW_SECURITY_PASSWORD_RESET_TTL (reset-link lifetime, default PT1H), and ACCESSFLOW_SECURITY_PASSWORD_RESET_RESET_BASE_URL (link base, default http://localhost:5173).

User roles & RBAC

What it is. Role-based access control. Every user carries one org-wide role that caps what they can do; on top of it, per-datasource permissions decide which databases they may touch. Pick the lowest-privilege role that still lets someone do their job — and a user can never approve their own query, whatever their role.

Custom roles. Beyond the five built-in system roles, an admin can compose custom roles on /admin/roles from a fixed catalog of functional permissions (submit SELECT/DML/DDL, review queries, review access requests, manage datasources, view the audit log, and so on) — e.g. a reviewer who may approve queries but not manage users. The five system roles are immutable and behave exactly as the matrix below; a custom role grants exactly the permissions you tick. Roles that are still assigned to users cannot be deleted.

Configure it. Assign a system or custom role when you create or edit a user on /admin/users; the matrix below is what each built-in role may do.

Platform admin is separate from the four roles. The platform-admin capability is an orthogonal flag, not a fifth role — a platform admin keeps whatever role their home org assigns and is additionally allowed to manage organizations across the cluster (/admin/organizations). It grants no extra capability inside any single org; the matrix below still governs every tenant-scoped action.

Capability READONLY ANALYST REVIEWER ADMIN AUDITOR
Submit SELECT queries
Submit DML (INSERT / UPDATE / DELETE)
Submit DDL (CREATE / ALTER / DROP)
View own query history
View all queries in the org
Approve / reject queries
Request time-bound datasource / API-connection access (JIT)
Review / approve access requests
Manage datasources
Manage users
Manage user groups
Manage review plans
View audit log
Manage notification channels
Configure AI
Configure SAML / OAuth
View / export compliance reports
View behavioural anomalies (UBA)
Acknowledge / dismiss anomalies
Break-glass / emergency execution
View break-glass log
Acknowledge break-glass events

Break-glass / emergency execution is not granted by role — it is gated by a separate per-user, per-datasource can_break_glass permission that an admin grants explicitly (required for everyone, including admins; time-boxed). A user can break glass only on a datasource they hold that grant for, and only for query types they already have the capability for.

Which role for what. Use READONLY for people who only need to look at production data (analysts, on-call engineers reading dashboards). Use ANALYST for people who write data through reviewed queries. Use REVIEWER for people who approve other users' queries — typically senior engineers or DBAs. Use ADMIN for the platform-team operators who configure the system itself. Use AUDITOR for a dedicated, read-only compliance reviewer — it sees only the compliance dashboard (/admin/auditor): pre-built PII/PCI/GDPR access and DDL/DELETE reports with signed PDF/CSV export, and nothing else.

Datasource-level permissions. Role is the org-wide ceiling. On top of it, every user needs an explicit per-datasource permission grant to access a given database — it controls read / write / DDL per datasource, row caps, allowed schemas / tables, and restricted columns (which are masked as *** in SELECT results). See docs/07-security.md for the full authorization matrix.

Group-based access grants. Rather than a row per person, an admin can grant a user group access to a datasource or an API connector (same read / write / DDL / break-glass controls); every member inherits the grant, and adding someone to the group gives them access without a new grant. When a user has both a direct grant and one or more group grants, their effective access is the most-permissive union — capabilities are OR-ed, allow-lists merge, restricted-column masks apply only where every grant restricts, and each grant's expiry is honoured independently.

Just-in-time (JIT) access requests

Instead of an admin pre-granting a permission, any user can request temporary, scoped access from /access-requests — to a datasource (pick the capabilities they need — read / write / DDL — and an optional schema/table scope) or to an API connection (read / write plus an optional allow-list of specific operations from the connector's schema catalog), with a duration. The request runs through the same reviewer-eligibility and multi-stage approval engine as query review (a requester can never approve their own); API-connection requests route through the connector's assigned review plan. Admins are the backstop approver: an admin sees and can approve every pending access request from /admin/access-requests — even on resources with no review plan — so a request is never stuck waiting for an approver who was never configured. On final approval AccessFlow writes a time-boxed permission grant (expiring at now + duration) — a datasource permission, or an API-connection permission visible on the connector's Permissions tab alongside admin-granted rows; it's revoked automatically on expiry, and an admin can revoke an active grant early from /admin/access-requests. Tune the revocation cadence with ACCESSFLOW_ACCESS_GRANT_EXPIRY_POLL_INTERVAL (default PT5M) and the allowed duration window with ACCESSFLOW_ACCESS_MIN_DURATION / ACCESSFLOW_ACCESS_MAX_DURATION (defaults PT15M / P30D). A requester can additionally tick “Pre-approve queries under this grant” on the request form (off by default): while such a grant is active, queries it covers — matching capability and schema/table scope — skip human review entirely and are auto-approved with the grant and its approver recorded on the query detail and in the audit log. The flag is shown as a highlighted tag in the approval queue so the reviewer sees exactly what they authorize; auto-reject and escalation routing policies, high-risk AI verdicts, and open behavioural anomalies still override the fast-path.

The /admin/access-requests queue listing a pending just-in-time access request — requester, datasource, requested capabilities, duration, and approve / reject / revoke actions.
/admin/access-requests — pending JIT access requests; admins approve, reject, or revoke an active grant.

Break-glass / emergency access

For genuine emergencies — production is down and approvers are unreachable — an admin can grant a user the can_break_glass permission on a datasource (a checkbox on the permission grant, alongside read / write / DDL, time-boxed via the same expires_at). With that grant, an Emergency access button appears on the editor for that datasource: the user supplies a mandatory justification and the query executes immediately, bypassing review — but still through every proxy guard (schema/table allow-list, dynamic masking, row-level security, row caps). The grant is required for everyone, including admins. Each break-glass execution fires instant notifications to all admins (including PagerDuty), writes a prominently-tagged QUERY_BREAK_GLASS_EXECUTED audit row, and opens a mandatory retro-review on the /admin/break-glass log that an admin — never the submitter — must acknowledge after the fact. The executed query keeps its normal terminal state; the retro-review is tracked alongside it.

The AccessFlow break-glass log listing emergency-access executions awaiting an admin's mandatory retro-review acknowledgement.
/admin/break-glass — every emergency execution opens a mandatory retro-review here for an admin (never the submitter) to acknowledge.

User groups

What it is. Named, organisation-scoped collections of users. Use them to (1) bundle reviewers so you can attach a single group — instead of ten individual users — to a datasource as eligible reviewers, (2) grant a whole team data or API access (a datasource or API-connector grant on a group is inherited by every member, so you don't add a row per person), and (3) act as the target of IdP group mappings so SAML / OAuth2 logins keep membership in sync automatically.

Configure it. Manage groups from /admin/groups:

  1. Create a group. Go to /admin/groupsCreate group. Pick a name (e.g. Billing Reviewers) and an optional description.
  2. Add members. Open the group, click Add member, and pick users from the dropdown. Manually-added members are tagged Manual and stay put regardless of the IdP sync.
  3. Use the group. On a datasource's Reviewers tab (/datasources/<id>/settings), add the group as a reviewer. From that point on, members of the group can see and decide queries against that datasource (in addition to plan-approver rules). On the same page's Permissions tab (and an API connector's Permissions tab) you can also grant the group access — switch the grant target from User to Group and every member inherits the read / write / DDL / break-glass grant.
  4. Optional: IdP-managed memberships. Configure group_mappings on the SAML or OAuth2 admin pages so an IdP group claim auto-maps to the AccessFlow group. On every login, AccessFlow replaces the user's IdP-sourced memberships with the mapped set; Manual memberships are never touched.

Per-datasource reviewer scoping. Once a datasource has at least one assigned reviewer (a user or a group), only those reviewers see its queries. Datasources with none fall back to the review-plan approvers — so adopting groups is purely additive, no migration required.

User groups list at /admin/groups showing a table of groups with name, description, member count, created date, and edit/delete actions, plus a Create group button.
/admin/groups — organisation-scoped user groups; open one to manage members.