# Granular review permissions

> Control who can edit, comment, resolve, and approve — per user, per action.

2026-02-07 · Missy Fox

Control exactly who can resolve, reject, edit, and delete in each document — down to the action level.

## The problem

Document review is collaborative, but it's not a free-for-all. Legal needs reviewers who can comment but not resolve threads. Compliance needs approvers who can accept changes but not reject them. A junior team member should be able to add comments but not delete someone else's.

Most editors treat permissions as binary: you're either an editor or a viewer. Real review workflows need something more granular.

## Permission Resolver

The `permissionResolver` callback lets you decide, per user and per action, what's allowed. You define the rules. SuperDoc enforces them.

```typescript
const superdoc = new SuperDoc({
  permissionResolver: ({ permission, role, comment, currentUser }) => {
    if (permission === 'RESOLVE_OTHER') return role === 'editor';
    if (permission === 'COMMENTS_DELETE_OTHER') return false;
    if (permission === 'COMMENTS_DELETE_OWN') return true;
    // Return undefined to fall back to built-in defaults
  },
});
```

## Permissions you can control

The resolver receives a `permission` string for every sensitive action:


| Permission                | What it controls                                 |
| ------------------------- | ------------------------------------------------ |
| `RESOLVE_OWN`             | Resolve your own comments or tracked changes     |
| `RESOLVE_OTHER`           | Resolve other users' comments or tracked changes |
| `REJECT_OWN`              | Reject your own tracked changes                  |
| `REJECT_OTHER`            | Reject other users' tracked changes              |
| `COMMENTS_OVERFLOW_OWN`   | Edit your own comments (overflow menu)           |
| `COMMENTS_OVERFLOW_OTHER` | Edit other users' comments                       |
| `COMMENTS_DELETE_OWN`     | Delete your own comments                         |
| `COMMENTS_DELETE_OTHER`   | Delete other users' comments                     |
| `UPLOAD_VERSION`          | Upload document versions                         |
| `VERSION_HISTORY`         | Access version history                           |


## The resolver context

The callback receives everything you need to make a decision:

```typescript
permissionResolver: ({
  permission,    // The action being checked (e.g. 'RESOLVE_OTHER')
  role,          // Current user's role: 'editor' | 'viewer' | 'suggester'
  comment,       // The comment being acted on (if applicable)
  trackedChange, // The tracked change (if applicable)
  currentUser,   // The user performing the action
  isInternal,    // Whether the comment is internal
  defaultDecision, // What SuperDoc would decide without your resolver
}) => {
  // Return true to allow, false to block
  // Return undefined to use the built-in default
};
```

## Real-world patterns

### Legal review: only editors can resolve

```typescript
permissionResolver: ({ permission, role }) => {
  if (permission === 'RESOLVE_OWN' || permission === 'RESOLVE_OTHER') {
    return role === 'editor';
  }
};
```

### External collaboration: no one can delete others' comments

```typescript
permissionResolver: ({ permission }) => {
  if (permission === 'COMMENTS_DELETE_OTHER') return false;
  if (permission === 'COMMENTS_OVERFLOW_OTHER') return false;
};
```

### Strict review: viewers can't reject tracked changes

```typescript
permissionResolver: ({ permission, role }) => {
  if (permission === 'REJECT_OWN' || permission === 'REJECT_OTHER') {
    return role === 'editor';
  }
};
```

## Configuration

The resolver can be set at the top level or scoped to the comments module (module-level takes precedence):

```typescript
// Top-level
new SuperDoc({
  permissionResolver: ({ permission, role }) => { /* ... */ },
});

// Or module-level
new SuperDoc({
  modules: {
    comments: {
      permissionResolver: ({ permission, role }) => { /* ... */ },
    },
  },
});
```

## Get started

Pass a `permissionResolver` to your SuperDoc configuration. The callback runs on every permission-sensitive action - no middleware, no separate permission service.

[Read the docs]([https://docs.superdoc.dev/modules/comments#permission-resolver](https://docs.superdoc.dev/modules/comments#permission-resolver))

&nbsp;
