Users and Permissions in Frappe Framework (Version 15): Complete Documentation
Permissions in Frappe Framework define who can access what, and how they can interact with documents. Frappe v15 provides a highly flexible, metadata-driven permission system that controls access at the:
- User level
- Role level
- Document level
- Field level (Permission Levels)
- Rule level (User Permissions)
This system ensures secure, controlled access across ERPNext and all custom applications.
1. What Are Users in Frappe Framework?
A User is any person who can log into a Frappe or ERPNext system.
Each User has:
- Email/Username
- Roles
- Permissions
- Module access
- Preferences
- API keys (optional)
Users exist as a standard DocType: User.
User Types in Frappe v15
| User Type | Description |
| System User | Full user with role-based access |
| Website User | Portal-only access |
| Administrator | Superuser |
| Guest | Public user (read-only website access) |
2. Roles — The Foundation of Permissions
A Role is a label assigned to users to determine their access level.
Examples:
- System Manager
- Sales User
- HR User
- Stock User
- Employee
- Customer
Roles DO NOT automatically provide access.
They become meaningful when combined with Role Permissions.
3. Role Permission Manager (RPM) – Core of Access Control
Frappe v15 provides a centralized tool:
Role Permission Manager
(Location: Desk → Settings → Role Permissions Manager)
Using RPM, you can configure:
- Read
- Write
- Create
- Delete
- Submit
- Cancel
- Amend
- Export
- Report access
These permissions apply to the selected DocType.
4. How Permissions Work in Frappe v15
Permissions in Frappe follow a layered model:
Layer 1: Role-Based Permissions
Set at the DocType level.
Example:
Sales User → Can create Sales Order
Layer 2: User Permissions
Restrict link fields to specific allowed values.
Example:
A salesperson can only access customers assigned to them.
Layer 3: Document Sharing
Share specific documents with other users.
Example:
Share a single Sales Order with a colleague.
Layer 4: Advanced Permissions
Includes:
- Permission Levels
- Match Rules
- Custom Permission Queries
5. Permission Levels (Field-Level Permissions)
Every DocField can have a permission level (0,1,2…).
Level 0 = visible/editable to all users with access
Level 1+ = only accessible to roles with explicit permission at that level
Used for sensitive fields like:
- Salary
- API keys
- Secret tokens
- Confidential notes
Example:
| Field | Permission Level |
| employee_name | 0 |
| salary | 1 |
Then assign “HR Manager” role access to Level 1 fields.
6. User Permissions (Restricting Link Fields)
User Permissions restrict what VALUES a user can select in a Link field.
Example use cases:
- A sales user should only see their assigned customers
- An employee should only see their own attendance
- A warehouse user should only see their warehouse
Creating a User Permission
Go to:
User → User Permissions → Add
Select:
- Allow: Customer
- Value: ABC Traders
- Applicable For: Sales Order
Now, this user will only see ABC Traders in all Customer link fields.
7. Document Sharing
Document-level sharing overrides role permissions and grants access to specific documents.
Sharing options:
- Read
- Write
- Share
Example:
- Share a Sales Invoice with the Finance Head
- Share an Employee record with a Team Lead
Sharing does NOT modify system roles.
8. Standard Permission Rules (v15)
Frappe applies permissions based on:
- owner (document creator)
- docstatus (Draft/Submitted/Cancelled)
- Role permissions
- User permissions
- Sharing rules
Example:
A user can cancel a submitted document only if:
- DocType is submittable
- Role has Cancel permission
- Document is in Submitted state
9. Permission Query Conditions (Advanced)
Used for complex permission rules.
Define in hooks.py:
permission_query_conditions = {
"ToDo": "frappe.desk.doctype.todo.todo.get_permission_query_conditions"
}
Server-side function returns SQL WHERE clause.
Example:
def get_permission_query_conditions(user):
return f"(`tabToDo`.owner = '{user}')"
10. Controller Methods for Permission Logic
Python controller of a DocType can override:
has_permission()
Custom validation.
has_website_permission()
Controls portal access.
before_save, validate
Business rule enforcement.
Example:
def has_permission(doc, user):
if doc.department != frappe.db.get_value("Employee", {"user_id": user}, "department"):
return False
return True
11. Real-World Permission Examples
Example 1: Sales Users see only their customers
Use User Permissions for Customer.
Example 2: HR Manager sees all employees
Assign HR Manager role with full access.
Example 3: Department Manager sees documents from their department only
Use custom query conditions linked to department field.
Example 4: Restrict employee salary fields
Set Permission Level = 1
Give HR Manager access to Level 1 fields.
12. Troubleshooting Permissions (AEO-Friendly)
| Issue | Cause | Fix |
| Can’t see DocType | Role missing permission | Add Read permission in RPM |
| Records missing in list | User Permissions too restrictive | Remove unnecessary filters |
| “Not permitted” error | Permission Level mismatch | Assign correct level roles |
| Cannot submit document | Missing Submit permission | Update Role Permission Manager |
| API call fails with 403 | User lacks Doctype permission | Assign Read/Write/Create |
Use:
bench clear-cache
after permission changes.
13. Best Practices for Permissions in Frappe v15
- Assign minimal roles required
- Avoid giving System Manager to non-admin users
- Use User Permissions to filter sensitive data
- Keep Permission Levels clean and documented
- Avoid modifying Core DocType permissions—create custom Roles
- Use Sharing for exceptions instead of modifying system roles
Conclusion
Users and permissions in Frappe v15 provide a structured, secure, and flexible access-control system.
From roles and permission levels to user-specific restrictions and advanced query conditions, developers and administrators gain full control over who can access and modify data.
Understanding this system is essential for any ERPNext or Frappe application implementation.