Complete guide to the Cotonti access rights system: masks, bits, groups using the example of the Market module

Detailed guide to the Cotonti access rights system: bitmasks, symbols R, W, 1-5, A, user groups, database storage, management functions, and an example of the Market module installer.

1. Introduction

Cotonti is a flexible content management system that employs a sophisticated permission model. This model is built upon user groups, access objects, and bitmask permissions. Understanding this system is critical for developing modules, configuring access rights, and ensuring site security.

This guide provides a detailed explanation of how the permission system works in Cotonti, how symbolic masks ('R', 'W', '1''5', 'A') are formed, how they are converted to numeric values and back, how these permissions are stored in the database, and how to use them through the example of the Market module installer. The guide is based on analysis of the core Cotonti code (files functions.php and auth.php) and the Market module installer. All statements are supported by code, without speculation.

2. Fundamentals of Cotonti Permission System

2.1. User Groups

In Cotonti, each user belongs to one main group and can be a member of several additional groups. Groups define the user's base permissions. The core defines the following standard groups (constants):

ConstantNumeric ValueDescription
COT_GROUP_DEFAULT0Template for new groups (not used as a real user group)
COT_GROUP_GUESTS1Guests (unauthenticated visitors)
COT_GROUP_INACTIVE2Inactive users (registered but not activated)
COT_GROUP_BANNED3Banned users
COT_GROUP_MEMBERS4Regular registered users
COT_GROUP_SUPERADMINS5Administrators (superadmins)
COT_GROUP_MODERATORS6Moderators (if used)

These constants are declared in functions.php:

const COT_GROUP_DEFAULT = 0;
const COT_GROUP_GUESTS = 1;
const COT_GROUP_INACTIVE = 2;
const COT_GROUP_BANNED = 3;
const COT_GROUP_MEMBERS = 4;
const COT_GROUP_SUPERADMINS = 5;
const COT_GROUP_MODERATORS = 6;

Custom user groups can have IDs greater than 6; they inherit rules from COT_GROUP_DEFAULT (see details in the cot_auth_add_item() section).

2.2. Access Objects: area and option

Permissions in Cotonti are assigned not globally but to specific access objects. An object is identified by a pair:

  • area — a realm or module, e.g., 'page', 'forums', 'market'. This string defines the permission context.
  • option — a specific element within the area: a category code, a section ID, or the special marker 'a' (meaning the area as a whole). For structure categories, option usually matches their code.

For example, the right to read the category computers-components of the Market module is recorded as area = 'market', option = 'computers-components'.

When checking permissions, the function cot_auth($area, $option, $mask) uses these two parameters to find the corresponding bitwise permissions.

2.3. Bitmask Permissions

Permissions are stored as an integer, each bit of which corresponds to a specific action. This allows efficient packing of multiple permissions into a single number and quick checking using bitwise operations.

Cotonti defines the following permission bits (values from the cot_auth_getvalue() function):

SymbolBit (position)Decimal ValueDescription
R11Read — viewing objects
W22Write — adding/editing
134Special permission level 1 (module-defined)
248Special permission level 2
3516Special permission level 3
4632Special permission level 4
5764Special permission level 5
A8128Administration — managing rights and settings

The final numeric value is calculated as the sum of the values of the allowed bits. For example:

  • R → 1
  • RW → 1 + 2 = 3
  • R1 → 1 + 4 = 5
  • RW1A → 1 + 2 + 4 + 128 = 135
  • RW12345A → 1+2+4+8+16+32+64+128 = 255

3. Symbolic Permission Masks

For human convenience, permissions are written as a string of characters. Each character corresponds to one bit. The set of characters is strictly defined.

3.1. Symbols R, W, 15, A

  • R (Read) — permission to read or view the contents of an object.
  • W (Write) — permission to write, create, or modify an object.
  • 1, 2, 3, 4, 5 — five additional permission levels whose interpretation entirely depends on the module. In the core they have no fixed meaning, giving developers flexibility. For example, in the Market module one could assign:

    • 1 — permission to publish listings;
    • 2 — permission to edit others' listings;
    • 3 — permission to moderate (approve/reject);
    • 4 — permission to manage categories;
    • 5 — permission for extended settings.

    These meanings are not mandatory; each module decides how to use them.

  • A (Admin) — administration permission. Usually implies the ability to manage access rights to the object, as well as perform actions inaccessible to regular users.

3.2. Function cot_auth_getvalue(): mask → number

The function cot_auth_getvalue($mask) converts a symbolic mask into an integer. It is defined in auth.php:

function cot_auth_getvalue($mask)
{
    $mn['0'] = 0;
    $mn['R'] = 1;
    $mn['W'] = 2;
    $mn['1'] = 4;
    $mn['2'] = 8;
    $mn['3'] = 16;
    $mn['4'] = 32;
    $mn['5'] = 64;
    $mn['A'] = 128;

    $res = 0;
    $masks = str_split($mask);

    foreach ($masks as $k) {
        if(isset($mn[$k])) $res += $mn[$k];
    }
    return $res;
}

How it works:

  1. Initializes an array mapping symbols to values.
  2. Splits the input string into individual characters.
  3. For each character, if it exists in the array, adds its value to the result.
  4. Returns the sum.

Examples:

  • cot_auth_getvalue('R') → 1
  • cot_auth_getvalue('RW') → 3
  • cot_auth_getvalue('RW1A') → 135
  • cot_auth_getvalue('') → 0
  • cot_auth_getvalue('0') → 0 (the character '0' is added for convenience, value 0)

3.3. Function cot_auth_getmask(): number → mask

The reverse function cot_auth_getmask($rn) converts a numeric value into a symbolic mask. It is defined in auth.php:

function cot_auth_getmask($rn)
{
    $res = ($rn & 1) ? 'R' : '';
    $res .= (($rn & 2) == 2) ? 'W' : '';
    $res .= (($rn & 4) == 4) ? '1' : '';
    $res .= (($rn & 8) == 8) ? '2' : '';
    $res .= (($rn & 16) == 16) ? '3' : '';
    $res .= (($rn & 32) == 32) ? '4' : '';
    $res .= (($rn & 64) == 64) ? '5' : '';
    $res .= (($rn & 128) == 128) ? 'A' : '';
    return $res;
}

It checks each bit and appends the corresponding symbol. The order of symbols is fixed: R, W, 1, 2, 3, 4, 5, A.

Examples:

  • cot_auth_getmask(1)'R'
  • cot_auth_getmask(3)'RW'
  • cot_auth_getmask(135)'RW1A'
  • cot_auth_getmask(0)''

4. Storing Permissions in Database

4.1. Table cot_auth

All access permissions are stored in the cot_auth table (usually $db_auth). This table links user groups, areas, and options with numeric values of permissions and locks.

4.2. Record Structure and Keys

Each table record contains at least the following fields (based on usage in code):

  • auth_groupid — user group ID.
  • auth_code — area code, e.g., 'market'.
  • auth_option — object (option), e.g., category code, or 'a' for the whole area.
  • auth_rights — integer value of allowed permissions (sum of bits).
  • auth_rights_lock — integer value of locked permissions (bitmask of what cannot be changed via interface).
  • auth_setbyuserid — ID of the user who set the permissions (for audit).

Record uniqueness is ensured by the combination (auth_groupid, auth_code, auth_option). This means that for each group and each object (within an area) there is no more than one row with permissions.

When adding permissions via cot_auth_add_item(), one record is created for each group that does not have the skiprights flag set.

5. Permission Management Functions

5.1. cot_auth() — checking user permissions

The main function for checking current user permissions:

function cot_auth($area, $option = null, $mask = 'RWA')

Parameters:

  • $area — area (module).
  • $option — specific object (category code) or null. If null or '', then 'a' (the area itself) is assumed.
  • $mask — string of characters defining which permissions to check. Default is 'RWA', i.e., read, write, and administration are checked simultaneously (returns an array of results for each character).

Return value:

  • If $mask consists of a single character — returns bool.
  • If $mask contains multiple characters — returns an array [symbol => bool].

How it works:

  1. Creates an array of bit values ($mn).
  2. Splits $mask into characters.
  3. For each character, checks the corresponding permission of the current user using data from Cot::$usr['auth'] (permission cache built during authorization).
  4. Logs the check in Cot::$sys['auth_log'].

The function uses the bitwise & operator to check whether the required bit is set in the stored numeric permission value.

Usage example:

if (cot_auth('market', 'computers-components', 'R')) {
    // User can read this category
}

5.2. cot_auth_add_item() — adding permissions for an object

The function adds permission records for a new object (e.g., a category). Defined in auth.php.

function cot_auth_add_item($module_name, $item_id, $auth_permit = [], $auth_lock = [])

Parameters:

  • $module_name — area.
  • $item_id — object code (option), e.g., category code.
  • $auth_permit — array of allowed permissions by group. Format: [group_id => 'RW1']. If a group is not specified, it is taken from $cot_auth_default_permit.
  • $auth_lock — array of locks by group. Similarly supplemented from $cot_auth_default_lock.

Algorithm:

  1. Supplements $auth_permit and $auth_lock with default values (using the + operator, which preserves already set keys).
  2. For each group from the global array $cot_groups (if the group does not have skiprights set) creates a record:
    • Determines $base_grp: if group ID > COT_GROUP_SUPERADMINS (5), uses COT_GROUP_DEFAULT (0), otherwise the group ID itself.
    • Gets the symbolic masks from $auth_permit[$base_grp] and $auth_lock[$base_grp].
    • Converts them to numbers via cot_auth_getvalue().
    • Adds the record to the $ins_array.
  3. Inserts all records in one query via Cot::$db->insert(Cot::$db->auth, $ins_array).
  4. Calls cot_auth_reorder() and cot_auth_clear('all').

Important: If a group is missing from $auth_permit, the value from $cot_auth_default_permit will be used. Same for locks. This ensures that all groups receive permissions.

5.3. cot_auth_remove_item() — removing object permissions

function cot_auth_remove_item($module_name, $item_id = null)

Deletes all permission records for the specified object. If $item_id is not specified, all objects of the area are removed.

5.4. cot_auth_clear() — clearing permission cache

function cot_auth_clear($id = 'all')

Resets the permission cache of users so that changes take effect. With 'all', clears the cache of all users and guests.

5.5. cot_auth_reorder() — sorting permission table

Executes SQL ALTER TABLE ... ORDER BY ... to physically sort records in the cot_auth table. This speeds up queries when there are many records.

5.6. cot_auth_add_group() — registering a new group

function cot_auth_add_group($group_id, $base_group_id = COT_GROUP_MEMBERS)

Creates permission records for a new group by copying them from a base group. Used when dynamically creating groups.

5.7. cot_auth_remove_group() — removing a group from permissions

function cot_auth_remove_group($group_id)

Deletes all permission records for the specified group.

6. Default Permissions and Their Values

6.1. $cot_auth_default_permit — standard allowances

In auth.php, a global array is defined:

$cot_auth_default_permit = [
    COT_GROUP_DEFAULT => 'RW',
    COT_GROUP_GUESTS => 'R',
    COT_GROUP_INACTIVE => 'R',
    COT_GROUP_BANNED => '0',
    COT_GROUP_MEMBERS => 'RW',
    COT_GROUP_SUPERADMINS => 'RW12345A'
];

These values are used when a particular group is missing from the user-defined $auth_permit. Note: for COT_GROUP_BANNED it is '0' (no permissions), for superadmins — full set.

6.2. $cot_auth_default_lock — standard locks

$cot_auth_default_lock = [
    COT_GROUP_DEFAULT => '0',
    COT_GROUP_GUESTS => 'A',
    COT_GROUP_INACTIVE => 'A',
    COT_GROUP_BANNED => 'RW12345A',
    COT_GROUP_MEMBERS => '0',
    COT_GROUP_SUPERADMINS => 'RW12345A'
];

By default, for guests and inactive users, the A permission is locked (cannot give them admin rights through the interface). For banned and superadmins, all permissions are locked — their rights are rigidly fixed.

7. Market Module Installer: Usage Example

The Market module, upon installation, creates many categories and assigns permissions for them. Let's examine the key fragments of its installer.

7.1. Category Array $categories

Categories are described by an array, each element contains:

  • 'code' — unique category code (e.g., 'computers-components').
  • 'title' — name.
  • 'desc' — description.
  • 'path' — hierarchical path in the structure (e.g., '001.001').

Example fragment:

$categories = [
    [
        'code'  => 'computers-components',
        'title' => 'Computers & Components',
        'desc'  => 'Desktop computers, components, and peripherals.',
        'path'  => '001',
    ],
    // ...
];

7.2. Arrays $authPermit and $authLock

The installer defines custom permissions for Market categories, overriding the standard ones:

$authPermit = [
    COT_GROUP_DEFAULT      => 'RW1',
    COT_GROUP_GUESTS       => 'R1',
    COT_GROUP_INACTIVE     => 'R',
    COT_GROUP_BANNED       => '',
    COT_GROUP_MEMBERS      => 'RW1',
    COT_GROUP_SUPERADMINS  => 'RW12345A',
    COT_GROUP_MODERATORS   => 'RW1A',
];

$authLock = [
    COT_GROUP_DEFAULT      => '0',
    COT_GROUP_GUESTS       => 'W2345A',
    COT_GROUP_INACTIVE     => 'W12345A',
    COT_GROUP_BANNED       => 'RW12345A',
    COT_GROUP_MEMBERS      => '0',
    COT_GROUP_SUPERADMINS  => 'RW12345A',
    COT_GROUP_MODERATORS   => '0',
];

Note: for the COT_GROUP_MODERATORS (6) group, explicit values are set, although it is not present in the default arrays. This ensures correct permissions for moderators.

7.3. Installation Loop for Categories and Permissions

The installer sequentially creates each category using cot_structure_add(), and then, if the category is successfully created and $useDefaultAuth is false, adds permissions via cot_auth_add_item().

foreach ($categories as $cat) {
    $result = cot_structure_add('market', [...], $useDefaultAuth);
    if ($result === true && !$useDefaultAuth) {
        cot_auth_add_item('market', $cat['code'], $authPermit, $authLock);
    }
}

Explanation: cot_structure_add() may return true on success, an array with an error (if the category already exists), or false. The check $result === true prevents duplicate permission addition when the installer is run again.

8. Analysis of Masks Used in Market

8.1. Permissions by Groups ($authPermit)

GroupMaskNumeric ValueExplanation
COT_GROUP_DEFAULTRW11+2+4 = 7Template: new groups get read, write, level 1
COT_GROUP_GUESTSR11+4 = 5Guests can read and use level 1 (e.g., view contacts)
COT_GROUP_INACTIVER1Read only
COT_GROUP_BANNED''0No permissions
COT_GROUP_MEMBERSRW17Users: read, write, level 1
COT_GROUP_SUPERADMINSRW12345A255Full access
COT_GROUP_MODERATORSRW1A1+2+4+128=135Read, write, level 1, administration

8.2. Locks by Groups ($authLock)

GroupMaskNumeric ValueExplanation
COT_GROUP_DEFAULT00Nothing locked
COT_GROUP_GUESTSW2345A2+8+16+32+64+128=250All rights locked except R and 1
COT_GROUP_INACTIVEW12345A2+4+8+16+32+64+128=254All locked except R
COT_GROUP_BANNEDRW12345A255All rights fixed
COT_GROUP_MEMBERS00Nothing locked
COT_GROUP_SUPERADMINSRW12345A255Full lock (superadmin rights unchangeable)
COT_GROUP_MODERATORS00Nothing locked

Interpretation of locks:
A lock (auth_rights_lock) indicates which bits cannot be changed through the rights management interface. If a bit is set in the lock, the corresponding right is fixed and cannot be removed or added by a site administrator (except by direct database modification). For example, for guests all rights except R and 1 are locked, meaning the administrator cannot give guests W or A rights, but can change R and 1.

9. Common Mask Combinations and Their Meaning

Based on the bit system, many masks can be created. Here are frequently used combinations:

  • R — read only. Suitable for guest groups that are allowed to view.
  • RW — read and write. Standard for registered users in most modules.
  • R1 — read + level 1. For example, guests can see the object and additional information available at level 1.
  • RW1 — read, write, and level 1. Typical set for participants who can add materials.
  • RW12 — read, write, levels 1 and 2. Extended rights, e.g., for trusted users.
  • RW123 — read, write, levels 1–3. Can be used for moderators without admin rights.
  • RW1234 — even wider rights.
  • RW12345 — almost full access, but without administration.
  • RW12345A — full access, including administration.
  • A — only administration (rarely used alone, usually with other rights).
  • W — only write without read (illogical but possible).
  • 0 or empty string — no permissions.

Combinations can be arbitrary; the main thing is that they make sense for a specific module. Levels 1–5 can be used by a module for action gradation.

10. Permission Locks (auth_rights_lock)

10.1. Why Locks Are Needed

Locks prevent accidental or malicious changes to critical permissions through the admin interface. For example, if the A right is locked for guests, the administrator cannot accidentally give guests administrative rights by simply checking a box. The lock fixes the bit, and changing that bit through standard means becomes impossible.

10.2. Examples of Locks and Their Effect

Consider the lock mask for guests in Market: W2345A. This means bits W, 2, 3, 4, 5, A are locked. The administrator can change only bits R and 1 (remove or grant those rights). But even if they give guests the W right, it will not work because Cotonti checks only auth_rights, and the lock does not affect the actual permission value, only the ability to edit it. Nevertheless, the lock ensures that after installation, rights are not accidentally expanded.

For banned and superadmins, the lock RW12345A means their rights are fully fixed and cannot be changed through the interface.

11. Practical Recommendations for Module Developers

  1. Use cot_auth_add_item() to add permissions when creating new objects. This ensures that permissions are added for all groups with default values taken into account.
  2. Explicitly set permissions for groups if you want to deviate from the defaults. In the Market example, permissions are set for all standard groups, including moderators.
  3. Lock critical rights to prevent their modification. Especially important to lock A for guests and inactive users, and fully fix superadmin and banned rights.
  4. Remember default values: if you do not pass a group in $auth_permit, it will receive rights from $cot_auth_default_permit. This can lead to unexpected results if you intended to give the group fewer rights.
  5. Check permissions with cot_auth() in module code. Do not directly access Cot::$usr['auth'], as the function ensures correct handling of the 'any' option and logging.
  6. Clear the permission cache after programmatic permission changes using cot_auth_clear().
  7. Maintain uniqueness of the (area, option) pair. If the object already exists, do not add permissions again unless necessary.

12. Frequently Asked Questions (FAQ)

Question: What do digits 1–5 in masks mean?
Answer: They are five additional permission levels that a module can use at its discretion. The core imposes no semantics on them.

Question: How does R differ from 1?
Answer: R is the standard read permission, checked by the core for displaying objects. 1 is an additional permission that can mean anything (e.g., "see hidden fields"). The module decides how to interpret it.

Question: Can a user be given a right that is locked?
Answer: Through the interface — no, but technically you can change auth_rights directly in the database. The lock (auth_rights_lock) only prohibits changes through standard means.

Question: What happens if a lock is not specified for a group?
Answer: The value from $cot_auth_default_lock will be used. If you do not want to lock rights, explicitly specify '0'.

Question: How does permission checking work if a user belongs to multiple groups?
Answer: When building the ACL (cot_auth_build()), rights from all user groups are combined using bitwise OR. Thus the user gets the maximum rights from all their groups.

Question: Why is the cot_auth table needed and why not store rights in groups?
Answer: Rights are tied not only to groups but also to specific objects (categories). Groups define the general access level, while the cot_auth table allows flexible per-category permission configuration.

13. Conclusion

The Cotonti permission system is a powerful and flexible mechanism based on bitmasks. Understanding symbolic notations (R, W, 15, A) and the ability to correctly form permission and lock arrays enables developers to create secure and customizable modules. The Market module example demonstrates how to assign permissions to categories upon their creation, following Cotonti best practices. We hope this guide has helped you understand the intricacies of working with access rights.

15 minutes read Sodium Carbonate

Comments (0)

No comments yet
Only registered users can post new comments

Page Discussion in Telegram

Content author

webitproff

Offline

Sodium Carbonate

Last logged: 2026-08-28 16:59

About me briefly
Support and development of web projects on the CMF Cotonti: private messengers via the website, open and closed small social networks, trading platforms and marketplaces, freelance and services exchange portal, catalogs of goods from wholesale suppliers, dropshipping platforms, online stores, and much more.
View developments and download
Public portfolio of my works and developments
Telegram for messages
@webitproff
Telegram channel
@s/aBuyFILE
  • Page published: 2026-08-28 16:41
  • Last update: 2026-08-28 16:59
  • Language:

Similar pages

Файл admin.rights.php в Cotonti
1 Основное назначение файла admin.rights.php в системе Cotonti CMF: Файл admin.rights.php отвечает за управление правами
Dialog System v2.6.1 module Cotonti - чаты пользователей на AJAX
2 Модуль общения пользователей сайта через AJAX в виде диалогов, в режиме онлайн, без обновления страницы,  для сайтов на
User Blog • 2020-07-17 05:15 webitproff
"Xtra db row market" v.4.0.0: админ-панель и интеграция с Market Mass Edit
3 Плагин xtradbrowmarket 4.0.0: собственная панель управления и полная интеграция с Market Mass Edit Дата: 11 августа
User Blog • 2026-08-11 11:32 webitproff
«Hidden Groups» скрываем группы
4 Плагин «Hidden Groups» - Скрывает выбранные группы и/или их членов в различных разделах сайта фриланс биржи на CMS
User Blog • 2020-07-17 05:15 webitproff
HTML-шаблон admin.rights.tpl в Cotonti
5 описание шаблона "admin.rights.tpl" Шаблон "admin.rights.tpl" является частью