F5 StudioF5 Studio
Skip to main content

Permissions

F5 Board uses logical permission names. When the script needs to check access (/board admin gate, /badmin, force-delete), it asks for a logical name like admin. The permission block in framework_config.lua then decides which real identifier in which permission system gets checked.

This page covers all four mechanisms and how they compose.

TL;DR — Stock Behaviour

Out of the box, with the default configuration, "admin" maps to:

FrameworkCheck
QBCoreQBCore.Functions.HasPermission(src, 'admin')
QBoxIsPlayerAceAllowed(src, 'admin')
ESXxPlayer.getGroup() ∈ { 'admin', 'superadmin' }
ox_coreIsPlayerAceAllowed(src, 'admin')

So if you already manage admins via your framework's normal mechanism, you don't need to touch this config — just make sure the admin permission/group exists.

The Permissions Config Block

config/framework_config.lua
Config.Permissions = {
mode = 'auto', -- 'auto' | 'aceOnly'

perFramework = {
esx = nil, -- nil | 'auto' | 'aceOnly'
qb = nil,
qbx = nil,
ox = nil,
},

aceFallback = false, -- true → fall back to ACE when native returns false

nodes = {
admin = {
ace = 'admin',
esx = { 'admin', 'superadmin' },
qb = 'admin',
qbx = 'admin',
ox = 'admin',
},
},
}
FieldPurpose
modeGlobal mode — 'auto' (framework-native, optionally with ACE fallback) or 'aceOnly' (ACE only)
perFramework.<key>Per-framework override of mode. nil = use the global mode
aceFallbackIn 'auto' mode, if the native check returns false, also try ACE. OR semantics
nodesMaps each logical permission name to its real identifier in each system

Mode 1 — Framework-Native (default)

Config.Permissions = {
mode = 'auto',
aceFallback = false,
}

Each framework uses its own native mechanism. This is the recommended setup if you already manage admins through your framework's own system.

FrameworkNative mechanism
ESXxPlayer.getGroup() compared against nodes.<logical>.esx (single string or list)
QBCoreQBCore.Functions.HasPermission(src, nodes.<logical>.qb)
QBXIsPlayerAceAllowed(src, nodes.<logical>.qbx) (QBX is ACE-based by design)
ox_coreIsPlayerAceAllowed(src, nodes.<logical>.ox) (ox_core is ACE-based)
ESX list semantics

For ESX, nodes.admin.esx = { 'admin', 'superadmin' } means OR — any of those groups passes the check.

Mode 2 — ACE-Only

Config.Permissions = {
mode = 'aceOnly',
}

The framework's native check is bypassed entirely. Only IsPlayerAceAllowed(src, nodes.<logical>.ace) is consulted.

Use this when you manage permissions purely through add_ace / add_principal in server.cfg and don't want to use the framework's internal system (e.g. the users.group column on ESX).

server.cfg — ACE setup
add_ace group.admin admin allow
add_ace group.moderator moderator allow

add_principal identifier.steam:11000010abcdef12 group.admin
add_principal identifier.discord:123456789012345678 group.moderator

Mode 3 — ACE Fallback

Config.Permissions = {
mode = 'auto',
aceFallback = true,
}

In 'auto' mode, if the framework-native check returns false, the bridge also tries IsPlayerAceAllowed. OR semantics — either passing grants access.

This is useful when you have a mix of admins:

  • Some admins are flagged through the framework (users.group = 'admin' on ESX, or QBCore's permissions table)
  • Some staff have add_principal identifier.X group.admin in server.cfg

Both work without changes.

Default is false

By default aceFallback = false, so ESX uses its native groups as the single source of truth. Flip it to true if you also want add_principal identifier.X group.admin to pass.

aceFallback has no effect under mode = 'aceOnly' — that mode already uses ACE exclusively.

Mode 4 — Per-Framework Override

Config.Permissions = {
mode = 'auto',

perFramework = {
esx = 'aceOnly', -- on ESX, use ACE only
qb = 'auto', -- on QBCore, use the native QBCore check
qbx = nil, -- on QBX, inherit global ('auto')
ox = nil,
},
}

Per-framework value takes precedence over mode. Useful when you have multiple servers sharing one config or when you migrate between mechanisms gradually.

Custom Logical Permissions

The script ships with a single logical permission, admin. You can define your own and use them in your own integrations (the script itself only asks for admin, but the bridge exposes Bridge.HasPermission(src, name) for any name).

config/framework_config.lua
Config.Permissions = {
nodes = {
admin = {
ace = 'admin',
esx = { 'admin', 'superadmin' },
qb = 'admin',
qbx = 'admin',
ox = 'admin',
},

-- A new logical permission "moderator":
moderator = {
ace = 'moderator',
esx = { 'mod', 'admin', 'superadmin' },
qb = 'admin', -- QBCore has no built-in 'mod'; reuse admin
qbx = 'admin',
ox = 'admin',
},

-- A logical permission scoped to your dev team:
['f5board.dev'] = {
ace = 'f5board.dev',
esx = { 'developer' },
qb = 'admin',
qbx = 'f5board.dev',
ox = 'f5board.dev',
},
},
}

Then to use the custom name, change the relevant gate:

config/config.lua
Config.AdminCommand.permission = 'moderator'
Implicit nodes

If the script asks for a permission name not listed in nodes, the logical name is used as-is for every system. So Bridge.HasPermission(src, 'xyz') resolves to: xPlayer.getGroup() == 'xyz' on ESX, HasPermission(src, 'xyz') on QBCore, IsPlayerAceAllowed(src, 'xyz') on QBX/ox.

ACE Quick Setup Examples

Grant admin to a specific Steam ID

server.cfg
add_ace group.admin admin allow
add_principal identifier.steam:110000110abcdef group.admin

Grant a custom permission to a Discord role group

server.cfg
add_ace group.f5board_dev f5board.dev allow
add_principal identifier.discord:123456789012345678 group.f5board_dev

Direct ACE grant (no group)

server.cfg
add_ace identifier.steam:110000110abcdef admin allow

Common Recipes

Pure ACE (framework-independent)

config/framework_config.lua
Config.Permissions = {
mode = 'aceOnly',
aceFallback = false,
nodes = {
admin = { ace = 'admin', esx = nil, qb = nil, qbx = 'admin', ox = 'admin' },
},
}
server.cfg
add_ace group.admin admin allow
add_principal identifier.steam:XXX group.admin

ESX with users.group only (default)

config/framework_config.lua
Config.Permissions = {
mode = 'auto',
aceFallback = false,
nodes = {
admin = { esx = { 'admin', 'superadmin' } },
},
}

Set users.group = 'admin' in the DB or use /setgroup <id> admin (depending on your admin menu).

ESX with both users.group AND ACE

config/framework_config.lua
Config.Permissions = {
mode = 'auto',
aceFallback = true, -- key flip
nodes = {
admin = {
ace = 'admin',
esx = { 'admin', 'superadmin' },
},
},
}
server.cfg
add_ace group.admin admin allow
add_principal identifier.discord:XXX group.admin -- ACE admins
-- ESX admins: set users.group = 'admin' as usual

QBCore with permissions table only (default)

No config change needed. Use QBCore's normal permission flow:

qb permissions add <serverId> admin

or set the permissions JSON column in the players table.

Different gates for /board and /badmin

config/config.lua
Config.Command.permission      = 'admin'
Config.AdminCommand.permission = 'admin.super'
config/framework_config.lua
Config.Permissions.nodes = {
admin = {
ace = 'admin',
esx = { 'admin', 'superadmin' },
qb = 'admin',
qbx = 'admin',
ox = 'admin',
},
['admin.super'] = {
ace = 'admin.super',
esx = { 'superadmin' },
qb = 'admin',
qbx = 'admin.super',
ox = 'admin.super',
},
}

/board opens for any admin; /badmin only for super-admins.

Verifying Permissions

Enable the bridge startup log to confirm which framework and mode were detected:

config/framework_config.lua
Config.Bridge.debug = true

On boot you'll see:

[f5_board] bridge: framework=qb
[f5_board] bridge: inventory=qb

If a /board or /badmin call fails with notify_no_perm, enable the SECURITY debug category to see the rejection:

config/config.lua
Config.Debug.enabled = true
Config.Debug.categories.SECURITY = true

Then the server console shows rejections like:

[SERVER][SECURITY] [WARN] catalog_request_reject src=12 reason=no_perm
[SERVER][SECURITY] [WARN] admin requestList denied src=12

That tells you the permission check ran but returned false. From there, double-check your nodes.<logical>.<framework> mapping in framework_config.lua and the player's actual group / ACE membership.

See Also