Collaboration Permissions
InkLayer collaboration permissions control mutations in the annotator: who can create annotations and replies, and who can move, resize, edit, change status, or delete existing content. React and Vue share the same permission model; only the component binding syntax differs.
InkLayer does not provide login or authentication.
usermust come from your application. Permission decisions rely on a stable, trusteduser.id; no separateroleprop is required.
Quick Start
React
import { PdfAnnotator } from 'inklayer-react'
import type { AnnotationPermissions, User } from 'inklayer-react'
const currentUser: User = { id: 'alice', name: 'Alice' }
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
export function ReviewDocument() {
return (
<PdfAnnotator
url="/document.pdf"
user={currentUser}
annotationPermissions={permissions}
defaultShowAnnotationAuthorLabels
layoutStyle={{ height: '100vh' }}
/>
)
}
Vue
<script setup lang="ts">
import { PdfAnnotator } from 'inklayer-vue'
import type { AnnotationPermissions, User } from 'inklayer-vue'
const currentUser: User = { id: 'alice', name: 'Alice' }
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
</script>
<template>
<PdfAnnotator
url="/document.pdf"
:user="currentUser"
:annotation-permissions="permissions"
default-show-annotation-author-labels
:layout-style="{ height: '100vh' }"
/>
</template>
Current User and Ownership
user represents the application user currently operating the annotator:
interface User {
id: string
name: string
}
iddrives permission decisions and must remain stable across user switches, reloads, and restored documents.nameis display metadata. It may change and should not be used for authorization.- When
idis empty or equals the default value'null',owner-onlytreats the current user as unauthenticated and denies every mutation. - Changing
userimmediately applies subsequent permission checks to the new current user.
Display Annotation Author Labels
defaultShowAnnotationAuthorLabels determines whether all annotation author labels are visible when the annotator initializes. It defaults to false in both React and Vue:
<PdfAnnotator defaultShowAnnotationAuthorLabels />
<PdfAnnotator default-show-annotation-author-labels />
falseonly keeps all labels collapsed by default; selecting an annotation still reveals that annotation’s author.- Users can use the author-label button in the annotation toolbar to keep all labels visible or hidden.
- Hold
Commandon macOS orAlton Windows/Linux to reveal all author labels temporarily. Releasing the key restores the previous state. - This prop sets the initial state; it is not a controlled switch for subsequent visibility changes.
- Labels use the author display information stored with each annotation. They help identify ownership but do not change
annotationPermissions; permission checks still rely on stable author IDs and the currentuser.id.
Permission Modes
annotationPermissions.mode supports two modes:
| Mode | Default behavior |
|---|---|
unrestricted | Default. Preserves the compatible behavior in which all annotation and reply mutations are allowed. |
owner-only | Valid users can create annotations and replies; only authors can manage their own content. |
Omitting annotationPermissions is equivalent to:
{ mode: 'unrestricted' }
owner-only Action Matrix
| Action | Annotation author | Other valid user | No valid user |
|---|---|---|---|
| Create an annotation | Allowed | Allowed | Denied |
| Reply to an annotation | Allowed | Allowed | Denied |
| Move or resize an annotation | Allowed | Denied | Denied |
| Edit an annotation | Allowed | Denied | Denied |
| Change annotation status | Allowed | Denied | Denied |
| Delete an annotation | Allowed | Denied | Denied |
| Edit or delete a reply | Reply author only | Denied | Denied |
The permission system restricts mutations only. Users can still view, select, and inspect annotations they cannot modify.
Override Defaults with can(request)
can is an optional synchronous resolver. InkLayer first calculates defaultAllowed from the selected mode, then calls can:
interface AnnotationPermissions {
mode?: 'unrestricted' | 'owner-only'
can?: (request: AnnotationPermissionRequest) => boolean | undefined
}
Return values:
| Return value | Result |
|---|---|
true | Force allow the current action |
false | Force deny the current action |
undefined | Keep the mode’s defaultAllowed result |
The request contains:
| Field | Description |
|---|---|
action | The requested mutation |
currentUser | Current user, or null when unavailable |
annotation | Current annotation; may be absent for create actions |
comment | Current reply; absent for non-reply actions |
defaultAllowed | The result already calculated by the current mode |
Supported Actions
type AnnotationPermissionAction =
| 'annotation.create'
| 'annotation.transform'
| 'annotation.edit'
| 'annotation.delete'
| 'annotation.comment'
| 'annotation.change-status'
| 'comment.edit'
| 'comment.delete'
Administrator Override
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
The administrator returns true; everyone else returns undefined and continues using the owner-only ownership rules.
Fully Read-Only Annotator
React:
<PdfAnnotator annotationPermissions={{ can: () => false }} />
Vue:
<PdfAnnotator :annotation-permissions="{ can: () => false }" />
Users can still select and inspect annotations, but every mutation is denied.
Deny Deletion
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ action }) =>
action === 'annotation.delete' ? false : undefined,
}
Lock a Document After Review
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) => {
if (documentLocked) return false
if (currentUser?.id === 'admin') return true
return undefined
},
}
documentLocked comes from your application’s document or approval state. In this order, a locked document also blocks administrators. Check the administrator first if administrators should bypass the lock.
canmust return synchronously. Load roles, document state, and approval data first, then provide them through a closure. Do not return aPromise. If the resolver throws, InkLayer denies the current action to avoid accidentally granting access.
Preserve Ownership When Saving
owner-only depends on persisted author IDs. Do not remove or rewrite these fields when saving and restoring annotations:
- Annotation
meta.authorId - Reply
user
meta.authorId may be a string ID or a user object:
annotation.meta.authorId = {
id: 'alice',
name: 'Alice',
}
If legacy data has no author information, InkLayer cannot establish ownership and those annotations cannot be edited in owner-only mode. During migration, populate authorship with real, stable IDs from your application.
Client Permissions Are Not a Security Boundary
annotationPermissions controls InkLayer UI and local browser mutations. It does not replace server-side authorization.
Your backend must still verify:
- Whether the current session may access the document
- Whether the current user owns an annotation being saved or deleted
- Whether administrator or approval privileges are valid
- Whether the submitted
authorIdmay be written
Never trust permission results, user IDs, or authorship submitted by the client without server validation.
Troubleshooting
Everything is disabled after enabling owner-only
Make sure user.id is non-empty and does not equal 'null'.
The current user cannot edit a restored annotation
Make sure persisted data retains annotation.meta.authorId and that it exactly matches the current user.id.
The administrator override does not work
Make sure can returns the boolean true and that the administrator ID matches currentUser.id. Returning undefined preserves the mode’s default decision.
Can can request permission data from the backend?
No. can is synchronous. Fetch business permissions first, then create or update annotationPermissions.