Access Hooks

The access hook feature allows to register a function on the server that intercepts the document modifications before the document gets saved to the database. It should only be used for access control, not to mutate the document.

A hook can return a permission error (with a 403 status property) which is consumed by the editor.

Example: Prevent Document Updates

Here you see a simple example which rejects a document update when the title is set to ’examplePermissionError'.

// server
liServer.registerInitializedHook(async () => {
  const accessControlApi = server.features.api('li-access-control')
  accessControlApi.registerHook(async ({action, nextDocument}) => {
    switch (action) {
      case 'document.update':
        if (nextDocument.metadata.title === 'examplePermissionError') {
          return accessControlApi.metadataPermissionError({
            message: 'Title cannot be "examplePermissionError"',
            metadataProperty: 'title'
          })
        }
        break
    }
  })
})

Advanced Document Update Example

In this example we only allow the server admin (which has userId = 1) to update a document which has the category ‘financialReport’. It’s only a showcase to get a feeling what you could do.

const accessControlApi = server.features.api('li-access-control')

// Hook parameters
// ---------------
// action          - document.create / document.update / document.get / document.delete / document.publish / document.unpublish
// projectId
// userId
// newDocument     - only available on action = 'document.create'
// documentVersion - stored document
// nextDocument    - document update which will be stored when the access check is valid
//
// RETURN
//   true or undefined or null - the document modification is allowed
//   throw an error            - the document modification will be rejected, the error will be shown in the editor
accessControlApi.registerHook(function ({action, projectId, userId, newDocument, documentVersion, nextDocument}) {
  switch (action) {
    case 'document.create': return true
    case 'document.update': return canUpdate(documentVersion, userId)
    case 'document.get': return true
    case 'document.delete': return canUpdate(documentVersion, userId)
    case 'document.publish': return canUpdate(documentVersion, userId)
    case 'document.unpublish': return canUpdate(documentVersion, userId)
  }
})

function canUpdate (documentVersion, userId) {
  const hasFinancialReport = documentVersion.metadata.category === 'financialReport')
  if (hasFinancialReport && userId !== 1) {
   throw accessControlApi.permissionError(
    'No user except the admin is allowed to edit documents in the category financialReport'
   )
  }
}