A magical new AL-based permission system

In this video, I take a look at the new AL-based permission system we got with version 18 of Microsoft Dynamics 365 Business Central. The permission system, behind the scene, is changed to use AL objects for permissions instead of maintaining permissions as data.

https://youtu.be/dS-kXOoGnzY

In this video, Erik walks through the brand new AL-based permission system introduced in Business Central version 18 (wave 1). While the user interface looks nearly identical to the old one, the underlying architecture has fundamentally changed: permissions can now be expressed as AL objects rather than being purely data-driven entries sitting in permission tables. Erik demonstrates how to create permission sets, organize them using includes, and touches on a PowerShell conversion tool for migrating existing permissions.

What Changed in Version 18?

For roughly 20 years, permissions in Business Central (and NAV before it) were entirely data-driven — they were stored as rows in permission tables. Starting with version 18, permissions can now be defined as AL objects. This is a major architectural shift, even though the end-user experience looks remarkably similar.

When you open the Permission Sets page in Business Central, you’ll notice a new Extension column. This tells you which extension (app) provided each permission set. For example, the Base Application provides a “Setup” permission set, the System Application provides a “Snapshot Debug” permission set, and the Company Hub app provides its own permission set — all defined as AL objects within their respective extensions.

Creating Permission Sets in AL

Erik demonstrates building permissions for a simple Point of Sale app (from a previous video in the series) that has just a single table: POS Setup.

Two New Object Types

AL now includes two new object types related to permissions:

  • Permission Set — defines a set of permissions
  • Permission Set Extension — extends an existing permission set from another app

Note that these new object types still require object numbers, even though recent AL object types have trended away from them.

A Basic Permission Set

Here’s a simple permission set that grants full access (Read, Insert, Modify, Delete) to the POS Setup table:

permissionset 50100 "POS Admin"
{
    Access = Public;
    Assignable = true;
    Caption = 'Point of Sale Admin';

    IncludedPermissionSets = "POS Setup Admin";
}

The Access Property: Public vs. Internal

Permission sets have an Access property with two options:

  • Public — combined with Assignable = true, this means the permission set can be assigned to users
  • Internal — the permission set cannot be assigned directly to users, but can be included in other permission sets

This lets you create a modular structure: internal permission sets handle specific areas, and public-facing permission sets compose them together.

permissionset 50101 "POS Setup Admin"
{
    Access = Internal;
    Caption = 'POS Setup Admin';

    Permissions = tabledata "POS Setup" = RIMD,
                  tabledata "General Ledger Setup" = RIMD;
}

Understanding the RIMD Permission Mask

In the broader development world, people talk about CRUD operations (Create, Read, Update, Delete). In Business Central, the equivalent is RIMD — Read, Insert, Modify, Delete — plus X for Execute (used on codeunits, reports, pages, etc.).

The case of the letters matters:

  • Uppercase (R, I, M, D, X) — direct access: the user can access the object directly
  • Lowercase (r, i, m, d, x) — indirect access: the user can only access the object through another object

For example, a user might have indirect insert access (i) to G/L Entry, meaning they can’t open the table and type entries directly, but Codeunit 12 (the posting codeunit) can insert entries on their behalf. In most typical scenarios, you’ll use uppercase for direct access.

Composing Permission Sets with Includes

One of the most powerful aspects of this new system is the ability to compose permission sets. You can create focused, internal permission sets and then include them in broader, user-facing ones:

permissionset 50103 "POS GL"
{
    Access = Internal;
    Caption = 'POS GL';

    Permissions = tabledata "General Ledger Setup" = RIMD;
}

permissionset 50102 "POS User"
{
    Access = Public;
    Assignable = true;
    Caption = 'Point of Sale User';

    IncludedPermissionSets = "POS GL";

    Permissions = tabledata "POS Setup" = R;
}

Even though “POS User” is composed of multiple permission sets, when you view it in Business Central, all the permissions are flattened and displayed together — the user sees exactly what access they have.

Cross-Extension Permissions

Your permission sets aren’t limited to objects within your own extension. You can grant access to tables, pages, codeunits, and other objects from other extensions as well.

A Warning About Wildcards

There is a wildcard syntax available — for example, tabledata * = RIMD — but Erik strongly warns against using it. It does not mean “all objects in my extension.” It means all objects in the entire system. This is equivalent to the old tabledata 0 = RIMD pattern. Be very reluctant to use the asterisk.

Permission Set Extensions

The permissionsetextension object type lets you extend permission sets defined by other apps. This is useful when your app needs to be part of an existing permission structure — you can add your objects to an existing permission set so that users with that set automatically get access to your app’s objects.

The Easy Copy-Paste Advantage

Because permissions are now code, you get all the benefits of working in a code editor: copy-paste, find-and-replace, version control, code review, and more. Creating a “User” variant of an “Admin” permission set is just a few keystrokes — change RIMD to R and update the name. Compare this to the old XML-based approach:

<PermissionSet>
  <Permission>
    <ObjectType>8</ObjectType>
    ...
  </Permission>
</PermissionSet>

Who can remember what object type 8 is? The old XML format was terrible to work with on many levels.

Converting Existing Permission Sets

If you already have permission sets that users have hand-crafted and curated over time, there’s a PowerShell tool available to convert them into AL objects. It’s located on the BCTech GitHub repository under the samples folder, in a project called Permission Set Conversion.

The module connects to a SQL Server database, extracts your current permission sets, and saves them as .permissionset.al files that you can then incorporate into your AL projects.

Using the Conversion Tool

First, you’ll need the SQL Server PowerShell module installed:

Install-Module SqlServer

Note: the required module is called SqlServer, not SQLPS — that would be too easy!

Then you can run the conversion:

Convert-PermissionSets -DatabaseServer localhost -DatabaseName W1 -Destination ".\NewPermissionSets"

How the Conversion Tool Works

The PowerShell module handles several key tasks:

  • Downloads symbols from the “Published Application” table to resolve object IDs to names and types
  • Queries permissions from both the Permission and Tenant Permission tables
  • Converts numeric permission masks to symbolic ones (e.g., permission value 1 becomes uppercase for direct access, 2 becomes lowercase for indirect access)
  • Generates proper AL files with the .permissionset.al extension

Here’s a look at the core of the permission mask conversion logic from the module:

function GetPermissionMask
{
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        $Permission
    )

    $PermissionMask = ''
        
    if ($Permission.'Read Permission' -eq 1)
    {
        $PermissionMask += 'R'
    } elseif ($Permission.'Read Permission' -eq 2)
    {
        $PermissionMask += 'r'
    }

    if ($Permission.'Insert Permission' -eq 1)
    {
        $PermissionMask += 'I'
    } elseif ($Permission.'Insert Permission' -eq 2)
    {
        $PermissionMask += 'i'
    }

    if ($Permission.'Modify Permission' -eq 1)
    {
        $PermissionMask += 'M'
    } elseif ($Permission.'Modify Permission' -eq 2)
    {
        $PermissionMask += 'm'
    }

    if ($Permission.'Delete Permission' -eq 1)
    {
        $PermissionMask += 'D'
    } elseif ($Permission.'Delete Permission' -eq 2)
    {
        $PermissionMask += 'd'
    }

    if ($Permission.'Execute Permission' -eq 1)
    {
        $PermissionMask += 'X'
    } elseif ($Permission.'Execute Permission' -eq 2)
    {
        $PermissionMask += 'x'
    }

    return $PermissionMask
}

The generated AL files include the proper Access, Assignable, and Caption properties, making them ready to incorporate into your projects with minimal editing.

Summary

The new AL-based permission system in Business Central version 18 is a significant improvement:

  • Permissions as code — defined in AL objects, versioned with your extension, and easy to manage
  • Composable — use IncludedPermissionSets to build modular, maintainable permission structures
  • Public vs. Internal — control which permission sets are user-assignable and which are building blocks
  • Extensible — use permission set extensions to add your objects to existing permission sets
  • Backward compatible — the user experience in the client is virtually unchanged
  • Migration path — the PowerShell conversion tool on BCTech helps you convert existing data-driven permission sets to AL objects

The result is something genuinely new and powerful that doesn’t break existing workflows — users can look at permissions with the same interface they’re used to, while developers finally have a proper, code-based way to define and ship permissions with their apps.