How to implement access controls and permissions in Solidity

Key takeaways:

  • Access controls and permissions in Solidity are critical for regulating access to functions within a smart contract.

  • They ensure that only authorized users can perform specific operations, enhancing the security and integrity of the contract and preventing unauthorized access or manipulation.

  • One effective approach to implementing access controls is Role-Based Access Control (RBAC). This involves defining state variables (such as contractOwner, admins, and users), creating a constructor to initialize these variables, and using modifiers like onlyContractOwner, onlyAdmin, and onlyUser to enforce access restrictions. The modifiers utilize require statements to validate the caller's identity before executing functions.

  • Implementing robust access controls in Solidity is essential for building secure decentralized applications.

Access controls and permissions in Solidity are techniques that regulate access to functions within a smart contract. They ensure that only authorized entities can perform certain operations. Solidity performs it using modifier and require statements, which enforce access restrictions and validate conditions before executing functions. Implementing access controls and permissions enhances the security and integrity of smart contracts by preventing unauthorized access and manipulation.

Implementation

There’re various methods to implement access controls and permissions in Solidity. One of those techniques is using Role-Based Access Control (RBAC). Let’s look at the following steps to get a better idea of its implementation:

Define contract

Define the contract and declare the required state variables initially. We are using solidity version 0.5.12 here.

pragma solidity ^0.5.12;
contract AccessControl {
address public contractOwner;
mapping(address => bool) public admins;
mapping(address => bool) public users;
}
  • Line 1: Add the version pragma in Solidity. It specifies the version of the Solidity compiler that should be used to compile the contract code.
  • Line 3–7: Define the contract and declare the state variables contractOwner, admins, and users to keep track of the contract owner, admin addresses, and user addresses, respectively.

Create constructor

Now create the constructor to initialize the contract owner and default admin:

constructor() {
contractOwner = msg.sender;
admins[msg.sender] = true;
}
  • Line 1–4: Assign the contract’s address to the contractOwner variable and mark the deployer as a default admin by setting admins[msg.sender] to true.

Create modifiers

Once the contract owner and default admin have been initialized, it’s time to set up the modifiers for role-based access control.

// Modifier for contract owner
modifier onlyContractOwner() {
require(msg.sender == contractOwner, "Only contract owner is allowed to call this function");
_;
}
// Modifier for admin
modifier onlyAdmin() {
require(admins[msg.sender], "Only admin is allowed to call this function");
_;
}
// Modifier for user
modifier onlyUser() {
require(users[msg.sender], "Only registered users are allowed to call this function");
_;
}
  • Line 2–3: The onlyContractOwner function verifies that the contract owner is the caller of a function. It uses a require statement to verify the condition; if it fails, it throws an error message.
  • Line 4: Represents the location where the modified function’s body will be executed.
  • Line 8–11: The onlyAdmin function verifies that the admin is the caller of a function. It checks if the caller’s address exists in the admins mapping, and if not, it throws an error.
  • Line 14–17: The onlyUser function verifies that the registered user is the caller of a function. It checks if the caller’s address exists in the users mapping; if not, it throws an error.

Implement functionalities for access control

Now let’s create functions to add or remove admins and register or stop user access. These functions can only be called by the contract owner or admins, respectively.

// Add an admin
function addAdmin(address admin) public onlyContractOwner {
admins[admin] = true;
}
// Remove an admin
function removeAdmin(address admin) public onlyContractOwner {
admins[admin] = false;
}
// Register a user
function registerUser(address user) public onlyAdmin {
users[user] = true;
}
// Stop the access of a user
function stopUser(address user) public onlyAdmin {
users[user] = false;
}
  • Line 2–9: These functions only allow the contract owner to add and remove an admin. It takes an admin address as a parameter and sets the corresponding admins[admin] mapping value to true and false.
  • Line 12–19: These functions only allow the admin to register and stop a user’s access. It takes a user address as a parameter and sets the corresponding users[user] mapping value to true and false.
pragma solidity ^0.5.12;

contract AccessControl {
    address public contractOwner;
    mapping(address => bool) public admins;
    mapping(address => bool) public users;

    constructor() {
        contractOwner = msg.sender;
        admins[msg.sender] = true;
    }

    // Modifier for contract owner
    modifier onlyContractOwner() {
        require(msg.sender == contractOwner, "Only contract owner is allowed to call this function");
        _;
    }

    // Modifier for admin
    modifier onlyAdmin() {
        require(admins[msg.sender], "Only admin is allowed to call this function");
        _;
    }

    // Modifier for user
    modifier onlyUser() {
        require(users[msg.sender], "Only registered users are allowed to call this function");
        _;
    }

    // Add an admin
    function addAdmin(address admin) public onlyContractOwner {
        admins[admin] = true;
    }

    // Remove an admin
    function removeAdmin(address admin) public onlyContractOwner {
        admins[admin] = false;
    }

    // Register a user
    function registerUser(address user) public onlyAdmin {
        users[user] = true;
    }

    // Stop the access of a user
    function stopUser(address user) public onlyAdmin {
        users[user] = false;
    }

}

Conclusion

In conclusion, implementing access controls and permissions in Solidity is essential for maintaining the security and integrity of smart contracts. By using techniques such as Role-Based Access Control (RBAC) and incorporating modifiers like onlyAdmin or onlyContractOwner, developers can ensure that only authorized entities can access or modify contract functions. These access controls help prevent unauthorized manipulation and safeguard the contract’s intended functionality. Whether managing admin privileges or user access, proper implementation of these techniques plays a critical role in building secure, trustworthy decentralized applications.

Frequently asked questions

Haven’t found what you were looking for? Contact Us


What is OpenZeppelin access control?

OpenZeppelin Access Control is a Solidity library that provides a robust framework for managing permissions in smart contracts. It allows developers to define roles, assign them to addresses, and enforce access restrictions on functions based on these roles.


What is access control in Solidity?

Access control in Solidity refers to mechanisms that restrict who can execute certain functions in a smart contract.


What is an access control list (ACL)?

An access control list (ACL) is a list of rules determining which users or system processes are granted access to particular resources and what actions (such as reading, writing, or executing) are allowed.


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved