UX Spec: Team Membership Control with ABAC Policies
Links
Resource | Link |
|---|---|
Figma — Team Membership Policies | |
Parent spec — ABAC Phase 1 (channels) | |
Sibling spec — ABAC Phase 2 (channel admin controls) |
1. Overview
1.1 Problem Statement
Membership Policies enforce ABAC on channels but not on teams. Admins must manage team membership manually even when channel access rules are in place. Users failing channel checks may still join or be invited to the parent team, browse public channels, view the member roster, and infer program context. This "hallway access" gap undermines least-privilege at the organizational boundary and creates audit findings in IL4/IL5 environments where teams map to classified programs.
1.2 Feature Summary
Team Membership Policies extend the existing Membership Policies system to teams. A single policy can now be assigned to channels, teams, or both. ABAC's behavior on a team depends on the team's access mode:
Public + ABAC — advisory. The team is visible to everyone. The Join button is enabled for all users. Qualifying users see a Recommended tag. Sync does not remove non-qualifying members. If auto-add is on, sync adds qualifying users.
Private + ABAC — strict. The team is invisible to non-qualifying users. Join requests are denied with a generic message. Sync removes non-qualifying members. If auto-add is on, sync also adds qualifying users.
Admins manage team assignments from the same policy editor in the system console as currently used for channels. Team Admins see policy status in Team Settings and can configure custom rules that compose additively with system rules. Auto-add is a per-team toggle that propagates the policy as automated team-membership backfill. Group sync and ABAC are mutually exclusive on the same team.
1.3 Scope
In scope for MVF:
Teams as an assignable resource type on Membership Policies
System Console Team Configuration page: new Membership policies and Custom access rules sections
Team Settings restructured into four tabs: Info / Access / Team Membership / Channel Membership
Mode-dependent enforcement: advisory on public, strict on private (including server-side directory filtering of private+ABAC teams from non-qualifying users)
Auto-add for teams: per-team toggle, initial-population scan on first attach or first enable, system DM notifies added users
"Recommended" tag in team directory for public+ABAC teams the viewer qualifies for
Sync Job Details modal extended with a Teams tab and per-team drill-down
Group sync ⨂ ABAC mutual exclusivity
2. Terminology
Term | Definition |
|---|---|
Membership Policy | An ABAC policy that defines attribute conditions for resource access. A single policy can be assigned to channels and teams. Created and managed by System Admins. |
Custom access rules | Team-level rules configured by a Team Admin in Team Settings. Additive to any system policy — a user must satisfy both. Custom rules cannot relax a system policy. |
Auto-add | Per-team toggle. When on, sync adds qualifying users who are not yet members. Additive only — turning it off does not remove members. |
Advisory ABAC | Behavior on public teams. Rules drive the Recommended tag and optional auto-add but do not gate join or directory visibility. |
Strict ABAC | Behavior on private teams. Rules gate directory visibility, join evaluation, and removal at sync. |
Policy sync | The batch job that evaluates all policies against assigned resources and adds or removes members accordingly. |
3. Admin Configuration
3.1 System Console: Policy Editor
Figma: Policy Editor — node 8203:10807
The policy editor is a System Console page. The Access Rules section is unchanged from the channel-only version. The "Applies to" section now has Channels and Teams tabs with live counts; each tab holds a searchable, filterable, paginated list with an Add action.
The Teams tab shows each team's discoverability mode (Public or Private) alongside its name, so the admin can see at a glance which assignments will enforce strictly and which will be advisory. The tab also adds an Auto-add members column with a per-team On/Off toggle. Turning auto-add on for a team from here triggers the same initial-population scan as toggling it on from Team Settings.
Save confirmation. On save: "Policy will be applied to {N} channels and {M} teams. {X} members on private+ABAC teams do not currently meet criteria and will be affected at next sync." Sync runs both team and channel evaluation in a single batch.
Empty-team warning (private+ABAC only). If the rules would remove all members from any assigned private+ABAC team, show on save: "Warning: The access rules for this policy would remove all members from the following team(s): [Team Name(s)]. These teams will become empty until users matching the rules are added. Do you want to continue?" System Admins retain access to empty teams.
Policy deletion. Delete is disabled until the policy has 0 channels and 0 teams assigned. Tooltip on the disabled state: "Remove all teams and channels from this policy before deleting."
Policy list view. Each row shows assigned counts (e.g., "3 channels, 2 teams").
3.2 System Console: Team Configuration
Location: System Console > Teams > [Team Configuration]
Figma: Team Configuration — node 8393:35837
The Team Configuration page is updated with two new sections and a master switch that govern attribute-based team membership:
"Manage membership with attribute based membership policies" switch — top-level toggle that enables ABAC for this team. When off, the Membership policies and Custom access rules sections are hidden. When on, both sections become visible and editable.
Membership policies section — lists every system-level Membership Policy applied to this team in a Policy Name / Actions table. An Add policy button opens a picker; per-row actions let the admin open the policy in the editor or remove it from the team. A team can have multiple policies applied; users must satisfy all of them to qualify (AND composition). When no policies are attached, the section shows an empty state with the Add policy action.
Custom access rules section — mirrors the channel-level custom access rules editor. Same three-column table (User Attribute / Operator / Values), same chip-style values, same Test matching users button. Below the rules, an Auto-add members based on access rules checkbox toggles auto-add for the team. Rules added here compose with any attached Membership policies under AND.
Disconnect a policy. The per-row Remove action on the Membership policies table opens a confirmation: "Remove this team from policy '[Policy Name]'? This team's membership will no longer be governed by this policy's rules. Existing members are retained; the team returns to its standard access mode at next sync." Buttons: Remove policy (destructive) / Cancel. On confirm, an audit entry is generated.
3.3 Team Settings — four tabs
Figma (structure + icons): node 8393:30728
Tab | Icon | Purpose |
|---|---|---|
Info |
| Team identity (existing) |
Access |
| Discoverability and admission mechanisms |
Team Membership |
| NEW — system policy indicator, custom rules editor, auto-add toggle |
Channel Membership |
| Existing channel admin surface, renamed |
Tab 1 — Info
Team name, description, icon. Existing surface, unchanged.
Tab 2 — Access
Discoverability and admission mechanisms. Available on every license tier.
Public Team / Private Team cards (channel-style pattern). Switching modes re-shapes ABAC's effect (advisory ↔ strict) at the next sync.
Invite code with a Regenerate button.
Email domain switch — "Only specific email domains can join this team," with a nested comma-separated domain list when enabled.
Group sync switch. Disabled when a Membership Policy is applied. Inline note: "Group sync is unavailable while a Membership Policy or Attribute-based membership rules are applied. "
When ABAC is applied, no Access tab control is disabled by ABAC itself — only Group Sync (which is architecturally mutually exclusive) becomes unavailable.
Tab 3 — Team Membership
System policy indicator (when applicable). Non-dismissible InfoBanner: "This team has a system-level membership policy applied: [Policy Name]. Any custom access rules you set here will be applied in addition to this policy."
Custom access rules editor. Section title "Who can join this team." Three-column table — User Attribute / Operator / Values — with chip-style values. Basic Mode only; no CEL editor.
Auto-add toggle. Checkbox below the rules table, label "Auto-add members based on access rules," helper "Users who match the configured attribute values will be automatically added as members."
Turning auto-add on runs a scan of all workspace users. Matching users not already members are added immediately.
Subsequent syncs add newly qualifying users.
Auto-add is additive only — turning it off does not remove members.
Deactivated users are skipped. Guests are never auto-added.
Each added user receives a system bot DM: "You've been added to [Team Name] because you meet the team's membership policy."
Test matching users. Button below the rule editor previews the matching users similar to how it works in channel settings.
Save validation.
Required fields — missing attribute or value highlights the field and shows "Please select an attribute and value."
Self-exclusion — if the rules would exclude the saving Team Admin, block save with "You cannot set these rules because that will remove you from the team."
Confirmation modal on save — if changes will add (auto-add on) or remove (private+ABAC) members, summarize the impact with View users (Allowed / Restricted / Added).
Membership changes apply immediately on save, not deferred to batch sync.
Tab 4 — Channel Membership
Existing channel admin surface, renamed from "Channel Policies." Functionally unchanged in this release. See the ABAC Phase 2 spec for behavior details.
3.4 Add Teams modal
Trigger: "Add teams" in the system console policy editor's Teams tab.
Modal title: Add Teams to Policy. Chip-bar typeahead with an Add button to the right of the bar. Selected teams appear inline as chips.
3.5 Sync job details
The System Console section is renamed to Membership sync jobs. The history table, the Run sync job action, and the per-row View details / Cancel actions are unchanged from the channel-only version.
Sync execution order:
Evaluate team membership rules for all assigned teams
For private+ABAC teams — remove users who no longer qualify (cascades channel removals)
For teams with auto-add on (either mode) — add qualifying non-members
Evaluate channel membership rules and apply removals and channel-level auto-adds
Sync Job Details modal adds a Teams tab alongside the existing Channels tab. Row counts show +N adds and -M removals. Clicking a Teams row opens a Team members drill-down with Added / Removed tabs, a search field, and pagination. Removed users show avatar, display name, and @handle only — no per-user removal reason is surfaced inline.
4. End-user flows
4.1 Team directory and Join
Public + ABAC. The team is listed for everyone. The Join button is enabled regardless of qualification. Qualifying users see a Recommended tag (lightbulb-outline icon + "Recommended" chip) next to the team name. The tag is suppressed if the user is already a member or has already been auto-added.
Private + ABAC. The team is filtered out of the directory entirely for non-qualifying users — they have no way to enumerate it. Qualifying users see the team normally and Join works as usual. In the rare race where qualification is lost between render and Join, the request is denied with the generic message "You do not meet the requirements for this team. Contact your admin."
4.2 Invitations
All invitations are evaluated at acceptance time in addition to the filtering when they are sent. In the invite people to team modal, we show a notice informing the user about membership rules applied to the team.
Add People modal — functional restriction. On private+ABAC, the candidate-search endpoint filters non-matching users server-side; they never appear in suggestions. On public+ABAC, all users appear.
The user can still type in any email and send the invite to that email. However, that user will only get access if their attributes match the attributes required to join the team at the time of acceptance:
Public + ABAC: acceptance always succeeds.
Private + ABAC: acceptance is denied with the generic message if the recipient does not qualify. The invitation link is consumed either way.
Admin "Add to Team": on private+ABAC, non-qualifying do not show in the search and the add is blocked. On public+ABAC, no filter.
API direct add: on private+ABAC, returns 403 with
reason: "policy_denied"and no policy metadata.
Pending invitations when ABAC is attached. Existing pending invitations remain valid. There is no mass invalidation. The acceptance flow simply evaluates ABAC as it would for any join attempt.
4.3 Member surfaces (qualifying users)
Members of a policy-governed team see the attribute requirements via a notice in the Manage Members modal and the Add People modal.
4.4 Policy sync and member removal
Sync behavior depends on the team's mode and auto-add state:
Team mode | Auto-add | Sync removes non-qualifying | Sync adds matching |
|---|---|---|---|
Public + ABAC | Off | No | No |
Public + ABAC | On | No | Yes |
Private + ABAC | Off | Yes | No |
Private + ABAC | On | Yes | Yes |
Removal flow (private+ABAC)
All members are evaluated against the team's combined rules (system policy AND custom rules).
Non-qualifying members are removed from the team.
Cascading removal: removed users lose membership in all channels within that team.
Each removed user receives a system bot DM (shield-with-X icon): "You have been removed from [Team Name] because you no longer meet the membership requirements. Contact your System Administrator for assistance."
Audit entries are generated per removed user and per cascaded channel removal.
Mass removal guardrail: if sync would remove more than 50% of a team's members, a warning is surfaced in sync results.
Addition flow (auto-add on)
All eligible workspace users (excluding deactivated users and guests) are evaluated against the combined rules.
Qualifying non-members are added.
Each added user receives the auto-add DM described in §3.3.
Audit entries are generated per added user.
Initial-population scan. When a policy is first attached to a team, or when auto-add is toggled from off to on, a one-time scan of all workspace users runs. The expected member count is shown in the save confirmation modal. The scan is reported as a single batch event with itemized per-user adds in the drill-down.
Known limitation
A policy may, at save time, exclude every Team Admin from a private+ABAC team — leaving no qualifying admin to manage it. The spec does not currently block this; admins should manually verify admin coverage before saving restrictive policies. A proactive guardrail and recovery path are planned for a future release.
4.5 Group sync mutual exclusivity
A team cannot have both group sync and an ABAC Membership Policy. The constraint is enforced at the API layer.
Add Teams modal: group-synced teams appear disabled.
Enabling group sync on a team with ABAC: confirmation dialog — "This team is currently governed by a membership policy. Enabling group sync will remove this team from the policy and transfer membership control to group sync. Continue?"
Assigning ABAC to a group-synced team via API: returns error "Cannot apply membership policy to group-synced team."
5. Edge cases
Scenario | Behavior |
|---|---|
Policy with no conditions (empty rule set) | All users meet criteria. On public+ABAC with auto-add on, the save confirmation warns the admin of the workspace-wide add count. |
User qualifies for team but fails channel policies inside it | Joins the team, sees restricted channels in the sidebar, cannot access them. Standard AND composition. |
User removed while actively posting (private+ABAC sync) | In-flight messages delivered. New actions rejected after revocation. |
Team at member capacity | Capacity error takes precedence over policy denial. No policy involvement is revealed. |
Network error during join (private+ABAC) | Fail-closed. "Unable to process your request. Please try again." No policy detail leaked. |
Mode flip Public → Private with ABAC attached | At next sync, ABAC switches from advisory to strict; non-qualifying members are removed. Admin is warned at the moment of the switch: "Switching to Private will activate strict ABAC. {N} current members do not meet criteria and will be removed at next sync." |
Mode flip Private → Public with ABAC attached | At next sync, ABAC switches from strict to advisory. No removals. Auto-add must be explicitly enabled if backfill is desired. |
Auto-add scan overlaps with manual add | Server-side dedup. Manual add wins in the audit log; auto-add becomes a no-op. |
Mode flip while sync is in flight | In-flight sync completes under the prior mode. The next sync operates under the new mode. |
Email-domain restriction in Access tab plus a conflicting | Both compose under AND. If the two disagree (e.g., one requires |
Disconnect leaves a policy with 0 resources | Policy persists as empty. Admin deletes it manually from the policies list. |
6. Roles & Permissions
Action | System Admin | Team Admin | End User |
|---|---|---|---|
Create/edit Membership Policies | Yes | No | No |
Assign teams to policies | Yes | No | No |
Configure custom rules in Team Settings | Yes | Yes (Basic mode) | No |
Toggle auto-add | Yes (System Console or Team Settings) | Yes (Team Settings) | No |
Disconnect a team from a policy | Yes | No | No |
Trigger batch sync | Yes | No | No |
Join private+ABAC team | Subject to policy | Subject to policy | Subject to policy |
Join public+ABAC team | Allowed | Allowed | Allowed |
See private+ABAC team in directory if not qualifying | No | No | No |
See Recommended tag (public+ABAC) | Yes (if qualifying) | Yes (if qualifying) | Yes (if qualifying) |
View denial reason | Full audit detail | No | Generic message only |
Admin roles do not bypass policy evaluation. A System Admin who does not satisfy a private+ABAC team's policy can manage the team's configuration but cannot join it as a member through the standard UI.
7. Accessibility
Recommended tag —
aria-label="Recommended based on your attributes". Icon paired with text (WCAG 1.4.1). Contrast ≥ 4.5:1 across all themes.Denial messages (private+ABAC) — announced via
aria-live="assertive"; focus moved to the message after the denied action.System policy banner in Team Settings —
role="status"so screen readers announce it without focus change.Auto-add and removal DMs — standard post accessibility; icons carry equivalent text alternatives.
All new icons and badges meet WCAG 1.4.3 contrast across the five Mattermost themes.
8. Licensing & SKU
Property | Value |
|---|---|
Feature available in | Enterprise Advanced (E20) |
Upsell trigger | Accessing System Console > Membership Policies on a non-E20 deployment |
Upsell message | "Membership Policies are available with Enterprise Advanced. Upgrade to enforce attribute-based access control on channels and teams." |
Below tier | Team policy UI is hidden. API endpoints return 403 with a license error. Teams operate with standard access modes only. |
9. Future considerations
Item | Rationale |
|---|---|
Proactive orphan-admin guardrail + recovery path | Prevent policies that would orphan a team of admins; provide a recovery mechanism for teams that become orphaned via attribute drift. |
Real-time enforcement via IDP webhook-triggered sync | Batch sync today; event-driven sync requires IDP integration work. |
Grace period before sync removal | Immediate removal is the defense-appropriate default; configurable grace adds complexity without current demand. |
Request Access workflow for non-qualifying users | Manual approval competes with the automated ABAC model. |
Advanced (CEL) mode editor in Team Settings | Basic Mode only for Team Admins; complex expressions require System Admin policies. |
Group sync + ABAC composability on the same team | Mutually exclusive today for simplicity. |
Channel-level auto-add parity with team auto-add | Limited parity exists; full alignment deferred. |