# How Macro Implements Channel-Based Permissions: Architecture and Code

> Discover how Macro implements channel-based permissions using a share-permission model and JWT tokens. Explore the architecture and code for secure access control.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: architecture
- Published: 2026-08-17

---

**Macro's channel-based permissions system uses a share-permission model built on the `ChannelSharePermission` struct, storing access levels in a database table and enforcing them via JWT tokens validated at runtime.**

The macro-inc/macro repository implements a robust authorization layer for collaborative documents through its channel-based permissions system. This architecture allows fine-grained control over who can view, comment on, or edit specific channels within a workspace. The implementation spans multiple crates and services, utilizing Rust's type system and PostgreSQL's atomic operations to ensure secure, consistent access control.

## Core Data Structures in the Permissions Model

### ChannelSharePermission and AccessLevel

The foundation of the system lives in [`crates/models_permissions/src/share_permission/channel_share_permission.rs`](https://github.com/macro-inc/macro/blob/main/crates/models_permissions/src/share_permission/channel_share_permission.rs), which defines the `ChannelSharePermission` struct. This struct stores a `channel_id` paired with an `AccessLevel`, representing a literal permission grant.

The `AccessLevel` enum, defined in [`crates/models_permissions/src/share_permission/access_level.rs`](https://github.com/macro-inc/macro/blob/main/crates/models_permissions/src/share_permission/access_level.rs), establishes a hierarchy of **View**, **Comment**, and **Edit** privileges. These levels implement comparison operators, allowing runtime checks using the `>` operator to verify if a user meets the required access threshold.

### UpdateChannelSharePermission Payload

Modifications to permissions flow through the `UpdateChannelSharePermission` struct, which carries an `UpdateOperation` enum with variants `Add`, `Remove`, and `Replace`. This payload structure enables atomic batch updates while maintaining type safety across API boundaries.

### Database Representation

The `ChannelSharePermissionRow` struct maps to the **`channel_share_permissions`** table, linking a `share_permission_id` to specific channels via `channel_id` and `access_level` columns. This relational design supports efficient querying and maintains referential integrity through foreign key constraints.

## Database Operations and Atomic Updates

Permission persistence relies on SQL `INSERT … ON CONFLICT … DO UPDATE` statements wrapped in the `create_channel_share_permissions` and `update_channel_share_permissions` functions. These routines accept slices of `ChannelSharePermission` objects, enabling batch operations that either establish new permissions or modify existing ones atomically.

When the Document Storage Service processes mutations, it utilizes the code in [`services/document_storage_service/src/outbound/entity_mutation.rs`](https://github.com/macro-inc/macro/blob/main/services/document_storage_service/src/outbound/entity_mutation.rs) to attach channel permissions to document requests, ensuring the database state remains synchronized with user intentions.

## Runtime Enforcement and JWT Validation

### Token Generation

The permission verification flow begins in the Document Storage Service, which generates JWT tokens embedding a `DocumentPermissionsToken`. This token contains a serialized list of `ChannelSharePermission` objects tied to the authenticated user, effectively packaging the user's channel access rights into a cryptographically secure format.

### Request Validation

The sync-service handles enforcement through [`services/sync-service/src/auth.rs`](https://github.com/macro-inc/macro/blob/main/services/sync-service/src/auth.rs), where incoming requests undergo JWT validation. The service extracts the channel permissions from the token and compares the stored `AccessLevel` against operation requirements using the enum's ordering logic. Requests failing this check receive an immediate `403 Forbidden` response, while authorized requests proceed to the handler.

## Implementation Examples

The following examples demonstrate practical usage patterns drawn from the macro-inc/macro source code.

### Creating a Channel Share Permission

```rust
use models_permissions::share_permission::channel_share_permission::{
    ChannelSharePermission, UpdateChannelSharePermission, UpdateOperation,
};
use models_permissions::share_permission::access_level::AccessLevel;

// Build a new permission granting Edit access to channel "c123"
let permission = ChannelSharePermission {
    channel_id: "c123".into(),
    access_level: AccessLevel::Edit,
};

// Persist it (inside an async context)
macro_db_client::share_permission::channel_permission::create::create_channel_share_permissions(
    &vec![permission],
).await?;

```

### Updating a Channel Permission via the API

```json
POST /api/v1/channel-permissions
{
  "operation": "replace",
  "channel_id": "c123",
  "access_level": "comment"
}

```

The handler converts this payload into `UpdateChannelSharePermission`, then calls the database routine with the `Replace` operation.

### Checking Permissions in Request Handlers

```rust
use models_permissions::share_permission::access_level::AccessLevel;

// `user_perms` is a Vec<ChannelSharePermission> extracted from the JWT
fn has_edit(user_perms: &[ChannelSharePermission], channel_id: &str) -> bool {
    user_perms.iter()
        .find(|p| p.channel_id == channel_id)
        .map_or(false, |p| p.access_level >= AccessLevel::Edit)
}

```

If `has_edit` returns `true`, the request proceeds; otherwise the service returns a `403 Forbidden` error.

## Summary

- **Core Abstraction**: The `ChannelSharePermission` struct in [`crates/models_permissions/src/share_permission/channel_share_permission.rs`](https://github.com/macro-inc/macro/blob/main/crates/models_permissions/src/share_permission/channel_share_permission.rs) represents user access to specific channels through a combination of `channel_id` and `AccessLevel`.
- **Persistence Layer**: Permissions store in the `channel_share_permissions` table via `create_channel_share_permissions` and `update_channel_share_permissions`, using atomic upserts to maintain consistency.
- **Access Hierarchy**: The `AccessLevel` enum defines View < Comment < Edit ordering, enabling runtime comparison operations for authorization checks.
- **Security Model**: The Document Storage Service packages permissions into JWT tokens as `DocumentPermissionsToken`, while the sync-service validates these tokens in [`services/sync-service/src/auth.rs`](https://github.com/macro-inc/macro/blob/main/services/sync-service/src/auth.rs) to enforce access control on every request.
- **Type Safety**: All permission structs derive `ToSchema` via utoipa, ensuring automatic OpenAPI documentation and API contract validation.

## Frequently Asked Questions

### What database table stores channel permissions in Macro?

The **`channel_share_permissions`** table persists channel access rights, with rows represented by the `ChannelSharePermissionRow` struct linking `share_permission_id` to specific `channel_id` values and their associated `access_level`.

### How does Macro handle atomic updates to multiple channel permissions?

The system uses PostgreSQL's `INSERT … ON CONFLICT … DO UPDATE` syntax wrapped in the `create_channel_share_permissions` and `update_channel_share_permissions` functions, accepting vectors of `ChannelSharePermission` objects to batch modifications atomically.

### What are the different access levels available in Macro's channel permissions?

The `AccessLevel` enum defines three hierarchical levels: **View**, **Comment**, and **Edit**. These levels support comparison operators, allowing code to check if a user's access meets or exceeds required thresholds using standard comparison syntax.

### How does the sync-service validate channel permissions?

The sync-service extracts `ChannelSharePermission` vectors from JWT tokens containing `DocumentPermissionsToken` claims, then validates requests against these permissions in [`services/sync-service/src/auth.rs`](https://github.com/macro-inc/macro/blob/main/services/sync-service/src/auth.rs), returning `403 Forbidden` for unauthorized operations.