5.1. Access Control in multi-server environment

LwM2M Client may be connected to more than one LwM2M Server. In such situation, restricting Server access to some part of the data model may be required.

To resolve this problem the LwM2M Specification defines an Access Control Object that allows setting specific access rights on data model Instances either during a Bootstrap Phase or normal runtime by properly authorized LwM2M Server.

In a multi-server environment every Object Instance (except Instances of the Access Control Object) has associated Access Control Instance:


Resource ID

Meaning of the value

Object ID


ID of the Object this instance targets

Object Instance ID


Object Instance ID this instance targets (also see the note below)



List of pairs (Short Server ID, Access mask) describing access rights assigned to LwM2M Servers

Access Control Owner


Short Server ID of the Server which owns this Access Control Instance (i.e. the one that can modify access rights)


65535 is a special Object Instance ID value reserved for use during the Bootstrap Phase and is valid only in combination with Create access flag.

5.1.1. ACL Resource

ACL Resource of the Access Control Object Instance is populated with pairs of form (Short Server ID, Access mask). Access mask is a combination of the following access flags (combined by bitwise OR operator):

Access flag

Allowed LwM2M Operations

Anjay representation

R (00001 binary)

Read, Observe


W (00010 binary)



E (00100 binary)



D (01000 binary)



C (10000 binary)




Discover operation is always allowed and LwM2M protocol does not provide a mechanism for forbidding it.

5.1.2. Note on data-model instances lifetime

Access Control Object also helps in managing Object Instance lifetime. Whenever some Object Instance is orphaned (i.e. no LwM2M Server is an Access Control Owner of the Access Control Instance associated with this Object Instance) it MUST be removed by the Client. Anjay’s pre-implemented Access Control Object does this automatically.


Of course, if necessary, you may implement your own Access Control Object and use it instead. Nonetheless it is worth noting that it is an extremely complex Object to implement in a correct way.

5.1.3. Example usage

In this example, we are going to setup multiple-server environment. We will assign LwM2M Server with SSID 1 the Create permission on the Test Object developed in another tutorial.

Additionally, we will allow both LwM2M Servers to read their respective LwM2M Server Instances.


What we do here is roughly equivalent to Factory Bootstrap phase, which is just one of the bootstrapping options. Same thing could be achieved by a Bootstrap Server, which in conformance with the LwM2M Specification would instantiate Access Control Object, and assign access permissions on its own in a multiple-server environment.

We start with installation of the Access Control, Security Object and Server Object modules:

int result = 0;
if (anjay_access_control_install(anjay)
        || anjay_security_object_install(anjay)
        || anjay_server_object_install(anjay)) {
    result = -1;

Then we setup two LwM2M Servers:

// LwM2M Server account with SSID = 1
const anjay_security_instance_t security_instance1 = {
    .ssid = 1,
    .server_uri = "coap://eu.iot.avsystem.cloud:5683",
    .security_mode = ANJAY_SECURITY_NOSEC

const anjay_server_instance_t server_instance1 = {
    .ssid = 1,
    .lifetime = 86400,
    .default_min_period = -1,
    .default_max_period = -1,
    .disable_timeout = -1,
    .binding = "U"

// LwM2M Server account with SSID = 2
const anjay_security_instance_t security_instance2 = {
    .ssid = 2,
    .server_uri = "coap://",
    .security_mode = ANJAY_SECURITY_NOSEC

const anjay_server_instance_t server_instance2 = {
    .ssid = 2,
    .lifetime = 86400,
    .default_min_period = -1,
    .default_max_period = -1,
    .disable_timeout = -1,
    .binding = "U"

// Setup first LwM2M Server
anjay_iid_t server_instance_iid1 = ANJAY_ID_INVALID;
anjay_security_object_add_instance(anjay, &security_instance1,
                                   &(anjay_iid_t) { ANJAY_ID_INVALID });
anjay_server_object_add_instance(anjay, &server_instance1,

// Setup second LwM2M Server
anjay_iid_t server_instance_iid2 = ANJAY_ID_INVALID;
anjay_security_object_add_instance(anjay, &security_instance2,
                                   &(anjay_iid_t) { ANJAY_ID_INVALID });
anjay_server_object_add_instance(anjay, &server_instance2,

And finally, we are ready to set access lists:

// Make SSID = 1 the owner of the Test object
anjay_access_control_set_owner(anjay, 1234, ANJAY_ID_INVALID,
                               server_instance1.ssid, NULL);

// Set LwM2M Create permission rights for it as well
anjay_access_control_set_acl(anjay, 1234, ANJAY_ID_INVALID,

// Allow both LwM2M Servers to read their Server Instances
anjay_access_control_set_acl(anjay, 1, server_instance_iid1,
                             server_instance1.ssid, ANJAY_ACCESS_MASK_READ);
anjay_access_control_set_acl(anjay, 1, server_instance_iid2,
                             server_instance2.ssid, ANJAY_ACCESS_MASK_READ);

That way we have ensured an exclusive access of Server with SSID 1 to Test Object (/1234) Instances.

Later on, this Server will be able to set some access rights for other Servers, by writing to proper Access Control Instances (i.e. Instances this Server is an owner of, which corresponds to instances it has created), but that’s outside of the scope of this tutorial. We recommend you to look at the LwM2M Specification for more details on Access Control Object, as well as at our API docs.


Please notice cleanup tag at end of main() function. It is important to delete your own implemented objects after calling anjay_delete(), as during the instance destruction Anjay may still try to refer to object’s data and premature object deletion could be disastrous in effects.

    return result;