MrPoulpi Labs
ox_target

Available scripts

FR
Documentation centre

Permissions and security

Admin and moderator groups, everyone, staff and admin levels, ox_target.<key> ACE, custom keys, client-side visibility and the checks really performed by the server.

Goal: decide who sees and who can use each option, knowing what the server really checks. Files: config.lua (AdminGroups, ModGroups, UseAcePermissions, Permissions) and server.cfg for ACE.

Levels

Value Access
'everyone' Everybody.
'staff' Groups from Config.AdminGroups or Config.ModGroups.
'admin' Groups from Config.AdminGroups.
{ 'group1', 'group2' } At least one of the listed groups. An empty list allows nobody.
false Nobody.
'otherKey' Same result as the otherKey key of Config.Permissions (up to 6 hops; beyond that or in a loop: refused).

Group membership is checked by Bridge.HasGroup:

  • ESX: xPlayer.getGroup() must be exactly equal to the group name. A superadmin player is not admin: list both if needed.
  • QBCore: QBCore.Functions.HasPermission, then the group.<name> ACE.
  • Others (qbx, ox, nd, standalone): IsPlayerAceAllowed(source, 'group.<name>'). If that test fails on your server, grant that ACE to the group explicitly, for example add_ace group.admin group.admin allow.
  • The server HasGroup(source, group) hook replaces all of the above.

Keys

Setting Type Default Effect
Config.AdminGroups string[] { 'admin', 'superadmin', 'owner' } Groups matched by the “admin” level (and “staff”).
Read by: protected engine, bridge/server.lua
Config.ModGroups string[] { 'mod' } Groups added to the “staff” level.
Read by: protected engine, bridge/server.lua
Config.UseAcePermissions boolean false true: the ox_target.<key> ACE also grants the matching permission, before groups.
Read by: protected engine
Config.Permissions table
{ staffMenu = 'staff', revive = 'admin',…{ staffMenu = 'staff', revive = 'admin', heal = 'admin', selfRevive = 'staff', selfHeal = 'staff', forceEmote = 'admin', forceMe = 'admin', weather = 'admin', giveKeys = 'admin', devTools = 'admin' }
Each key is everyone, staff, admin, a list of groups, false, or the name of another key. You can add your own keys.
Read by: protected engine

You can add your own keys and use them in the permission field of an option or a server action:

Config.Permissions = {
    staffMenu   = 'staff',
    revive      = 'admin',
    heal        = 'admin',
    selfRevive  = 'staff',
    selfHeal    = 'staff',
    forceEmote  = 'admin',
    forceMe     = 'admin',
    weather     = 'admin',
    giveKeys    = 'admin',
    devTools    = 'admin',
    emsTools    = { 'ambulance_chief', 'admin' },
}

Do not remove the ten original keys: a built-in whose key is missing becomes invisible and refused for everyone.

ACE

With Config.UseAcePermissions = true, the ox_target.<key> ACE grants the permission before the group check:

add_ace group.helper ox_target.selfHeal allow
add_ace identifier.license:0123456789abcdef ox_target.devTools allow

The ACE check repeats at every step of a reference: for selfHeal = 'staff', the ox_target.selfHeal ACE is enough, but so is ox_target.staff, which then opens every key set to 'staff'. The ACE does not replace the key: removing selfHeal from Config.Permissions makes the option invisible even with the ACE.

What the client does

The client receives a permission map from the server: every Config.Permissions key, the everyone, staff, admin levels, and the result for each custom server action. It requests it again every Config.Security.permissionRefresh ms and after the character loads. This map is only used to hide options.

Consequences:

  • An option whose permission is unknown to the map is always hidden.
  • A group change in game can take up to permissionRefresh ms to show in the menu.
  • An option’s jobs, groups and items fields are evaluated client side for display.

What the server checks

Built-ins that go through a server action and your server_action options are checked by the engine, in this order: known action, anti-spam, feature, integration availability, permission, job, arguments, target existence and distance (+ distanceTolerance), item. An abnormally refused request is reported (OnSuspiciousActivity or console).

Options without a server check in the archive: copy/show ID, /me input, anti-punch, Dev Tools copy tools, “take appearance”, appearance restore, local weather tools and invoices (validated by the billing script). The Rock Paper Scissors challenge and the trunk hideout have their own server checks (distance, availability).

Common mistakes

  • Staff option visible to everyone: the category has permission = 'staffMenu' but a child option was moved out of the submenu without a permission.
  • 'superadmin' refused under ESX: add it to Config.AdminGroups.
  • ACE without effect: Config.UseAcePermissions was left at false.

Search

Type a term: setting, export, error…