Permissions
Permissions control what actions users can perform in Taruvi Cloud. They provide fine-grained access control at the model and object level, supporting both Django's built-in permission system and Guardian's object-level permissions.
Overview
Taruvi Cloud uses a multi-layered permission system:
- Model-level Permissions: Control access to model types (e.g., can add/view/change/delete organizations)
- Object-level Permissions: Control access to specific instances (e.g., can manage Organization A but not Organization B)
- Group-based Permissions: Assign permissions through groups for role-based access control
- Guardian Integration: Object-level permissions for organizations, sites, and resources
Key Features
Two-Layer Permission System
Model-Level Permissions:
# User can create ANY organization
user.has_perm('core.add_organization')
# User can view ANY site
user.has_perm('core.view_site')
Object-Level Permissions:
# User can manage SPECIFIC organization
user.has_perm('core.manage_organization', organization_obj)
# User can access SPECIFIC site
user.has_perm('core.access_site', site_obj)
Permission Types
Permissions follow Django's standard CRUD pattern plus custom permissions:
add_<model>: Create new instancesview_<model>: View instanceschange_<model>: Update instancesdelete_<model>: Delete instances<custom>_<model>: Custom actions (e.g.,manage_organization,invite_members)
Using Permissions
Listing All Permissions
Get all available permissions in the system:
- REST API
- Python
- JavaScript
curl -X GET https://your-site.taruvi.cloud/api/cloud/permissions/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"count": 150,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Can add organization",
"codename": "add_organization",
"content_type": {
"id": 10,
"app_label": "core",
"model": "organization"
}
},
{
"id": 2,
"name": "Can view organization",
"codename": "view_organization",
"content_type": {
"id": 10,
"app_label": "core",
"model": "organization"
}
}
]
}
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/permissions/",
headers=headers
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/permissions/", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
const data = await response.json()
Filtering Permissions by Model
Filter permissions for specific models:
- REST API
- Python
- JavaScript
# Get all organization permissions
curl -X GET "https://your-site.taruvi.cloud/api/cloud/permissions/?model=organization" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Get all site permissions
curl -X GET "https://your-site.taruvi.cloud/api/cloud/permissions/?model=site" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Get all user permissions (includes User and OrganizationMember)
curl -X GET "https://your-site.taruvi.cloud/api/cloud/permissions/?model=user" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
# Get all organization permissions
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/permissions/",
headers=headers,
params={"model": "organization"}
)
data = response.json()
// Get all organization permissions
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/permissions/?model=organization", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
const data = await response.json()
Valid Model Values:
site- Site model permissionsorganization- Organization model permissionsuser- User and OrganizationMember permissions
Providing an invalid model value returns a 400 error with valid options.
Searching Permissions
Search permissions by name or codename:
- REST API
- Python
- JavaScript
curl -X GET "https://your-site.taruvi.cloud/api/cloud/permissions/?search=organization" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/permissions/",
headers=headers,
params={"search": "organization"}
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/permissions/?search=organization", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
const data = await response.json()
Getting Permission Details
Retrieve details of a specific permission:
- REST API
- Python
- JavaScript
curl -X GET https://your-site.taruvi.cloud/api/cloud/permissions/{permission_id}/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/permissions/{permission_id}/",
headers=headers
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/permissions/{permission_id}/", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
const data = await response.json()
Permission Structure
Permission Object
{
"id": 1,
"name": "Can add organization",
"codename": "add_organization",
"content_type": {
"id": 10,
"app_label": "core",
"model": "organization"
}
}
Fields:
id: Unique identifier for the permissionname: Human-readable descriptioncodename: Short identifier used in code (format:action_model)content_type: The Django model this permission applies to
Permission Codename Format
Permissions follow a consistent naming pattern:
<action>_<model>
Examples:
- view_organization
- add_site
- change_user
- delete_domain
- manage_organization (custom)
- invite_members (custom)
Core Model Permissions
Organization Permissions
| Permission | Codename | Description |
|---|---|---|
| View | view_organization | View organization details |
| Add | add_organization | Create new organizations |
| Change | change_organization | Update organization |
| Delete | delete_organization | Delete organization |
| Manage | manage_organization | Full management (custom) |
| Invite Members | invite_members | Send invitations (custom) |
| Manage Sites | manage_sites | Manage org sites (custom) |
Site Permissions
| Permission | Codename | Description |
|---|---|---|
| View | view_site | View site details |
| Add | add_site | Create new sites |
| Change | change_site | Update site settings |
| Delete | delete_site | Delete site |
| Access | access_site | Access site environment (custom) |
| Manage | manage_site | Full site management (custom) |
| Manage Users | manage_site_users | Manage site users (custom) |
| Admin | admin_site | Site administrator (custom) |
User Permissions
| Permission | Codename | Description |
|---|---|---|
| View | view_user | View user details |
| Add | add_user | Create new users |
| Change | change_user | Update user information |
| Delete | delete_user | Delete users |
Domain Permissions
| Permission | Codename | Description |
|---|---|---|
| View | view_domain | View domain configuration |
| Add | add_domain | Add new domains |
| Change | change_domain | Update domain settings |
| Delete | delete_domain | Remove domains |
Group Permissions
| Permission | Codename | Description |
|---|---|---|
| View | view_group | View group details |
| Add | add_group | Create new groups |
| Change | change_group | Update group permissions |
| Delete | delete_group | Delete groups |
Object-Level Permissions (Guardian)
Assigning Object Permissions
Object permissions are automatically assigned when:
- Creating an organization (owner gets all permissions)
- Adding members to organizations (configurable permissions)
- Creating sites within organizations (inherited from org)
- Inviting users (invitation-specific permissions)
Checking Object Permissions
The API automatically checks object-level permissions:
- REST API
- Python
- JavaScript
# This checks if user has view_organization permission on THIS specific organization
curl -X GET https://your-site.taruvi.cloud/api/cloud/organizations/{org_uuid}/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Returns 403 Forbidden if user lacks permission on this specific organization
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/organizations/{org_uuid}/",
headers=headers
)
# Returns 403 Forbidden if user lacks permission on this specific organization
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/organizations/{org_uuid}/", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
// Returns 403 Forbidden if user lacks permission on this specific organization
const data = await response.json()
Permission Inheritance
Permissions can be inherited:
- Organization members inherit permissions to organization's sites
- Site permissions can be granted independently
- Group permissions apply to all group members
Granting Permissions
Through Groups
The recommended way to grant permissions is through groups:
- REST API
- Python
- JavaScript
# Create a group with permissions
curl -X POST https://your-site.taruvi.cloud/api/cloud/groups/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Site Managers",
"permission_ids": [10, 11, 12, 13]
}'
import requests
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
response = requests.post(
"https://your-site.taruvi.cloud/api/cloud/groups/",
headers=headers,
json={
"name": "Site Managers",
"permission_ids": [10, 11, 12, 13]
}
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/groups/", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Site Managers",
permission_ids: [10, 11, 12, 13]
})
})
const data = await response.json()
Direct Assignment
Permissions can also be assigned directly to users, though this is not exposed through the standard API and should be done programmatically when needed.
Permission Checking in API
Authentication Required
All endpoints require authentication:
Authorization: Bearer YOUR_ACCESS_TOKEN
Without authentication, you'll receive:
{
"detail": "Authentication credentials were not provided."
}
Permission Denied
When lacking required permissions:
{
"detail": "You do not have permission to perform this action."
}
Common Permission Scenarios
Scenario 1: List Organizations
- REST API
- Python
- JavaScript
curl -X GET https://your-site.taruvi.cloud/api/cloud/organizations/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
- Returns only organizations user has
view_organizationpermission for - Empty list if no access
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(
"https://your-site.taruvi.cloud/api/cloud/organizations/",
headers=headers
)
data = response.json()
# Returns only organizations user has view_organization permission for
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/organizations/", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
const data = await response.json()
// Returns only organizations user has view_organization permission for
Scenario 2: Create Organization
- REST API
- Python
- JavaScript
curl -X POST https://your-site.taruvi.cloud/api/cloud/organizations/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "New Organization"}'
- Requires
add_organizationmodel permission - User automatically gets full permissions on created organization
import requests
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
response = requests.post(
"https://your-site.taruvi.cloud/api/cloud/organizations/",
headers=headers,
json={"name": "New Organization"}
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/organizations/", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "New Organization" })
})
const data = await response.json()
Scenario 3: Update Specific Organization
- REST API
- Python
- JavaScript
curl -X PUT https://your-site.taruvi.cloud/api/cloud/organizations/{uuid}/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Organization"}'
- Requires
change_organizationpermission on THAT specific organization - 403 Forbidden if lacks object-level permission
import requests
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
response = requests.put(
"https://your-site.taruvi.cloud/api/cloud/organizations/{uuid}/",
headers=headers,
json={"name": "Updated Organization"}
)
data = response.json()
const response = await fetch("https://your-site.taruvi.cloud/api/cloud/organizations/{uuid}/", {
method: "PUT",
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "Updated Organization" })
})
const data = await response.json()
Scenario 4: Delete Site
- REST API
- Python
- JavaScript
curl -X DELETE https://your-site.taruvi.cloud/api/sites/{uuid}/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
- Requires
delete_sitepermission on THAT specific site - Also checks parent organization permissions
import requests
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.delete(
"https://your-site.taruvi.cloud/api/sites/{uuid}/",
headers=headers
)
const response = await fetch("https://your-site.taruvi.cloud/api/sites/{uuid}/", {
method: "DELETE",
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
Best Practices
- Use Groups: Assign permissions through groups, not directly to users
- Least Privilege: Grant only necessary permissions
- Object-Level: Use object permissions for multi-tenant isolation
- Regular Audits: Review and update permissions regularly
- Custom Permissions: Create custom permissions for specific business logic
- Permission Naming: Follow consistent naming patterns
- Documentation: Document what each permission allows
Permission Hierarchies
Organization Hierarchy
Organization Owner
├── Full organization permissions
├── All site permissions
└── Can manage all members
Organization Admin
├── View and change organization
├── Manage members
├── Manage sites
└── Cannot delete organization
Organization Member
├── View organization
└── Access assigned sites only
Site Hierarchy
Site Admin
├── Full site management
├── Manage site users
├── Change site settings
└── Manage domains
Site Manager
├── View site
├── Change site settings
├── View site users
└── Cannot delete site
Site Viewer
└── View site details only
Common Permission Sets
Read-Only Access
{
"permissions": [
"view_organization",
"view_site",
"view_user",
"view_domain"
]
}
Content Manager
{
"permissions": [
"view_organization",
"view_site",
"change_site",
"view_user",
"add_domain",
"change_domain"
]
}
Organization Administrator
{
"permissions": [
"view_organization",
"change_organization",
"manage_organization",
"invite_members",
"add_site",
"view_site",
"change_site",
"delete_site",
"manage_site"
]
}
Platform Administrator
{
"permissions": [
"add_organization",
"view_organization",
"change_organization",
"delete_organization",
"manage_organization",
"add_site",
"view_site",
"change_site",
"delete_site",
"add_user",
"view_user",
"change_user",
"delete_user"
]
}
Security Considerations
Multi-Tenancy
Object-level permissions ensure:
- Users only see their organizations
- Site data is completely isolated
- Cross-tenant access is prevented
Permission Escalation
Prevent permission escalation by:
- Validating permission grants
- Checking parent object permissions
- Using Guardian's object permissions
- Regular permission audits
API Security
All API endpoints:
- Require authentication
- Check model-level permissions
- Verify object-level permissions where applicable
- Return appropriate error codes
Troubleshooting
"Permission Denied" Errors
If you receive permission denied errors:
- Check Authentication: Ensure you're logged in
- Verify Model Permission: Check if you have the base model permission
- Check Object Permission: Verify you have permission on that specific object
- Review Group Membership: Confirm you're in the right groups
- Contact Admin: Request necessary permissions
Permission Not Available
If a permission doesn't appear in the list:
- Run migrations: Permissions are created during migrations
- Check custom permissions in model Meta classes
- Verify ContentType exists for the model
- Review permission creation in migration files
Related Features
- Users - User accounts with permissions
- Groups - Group-based permission management
- Organizations - Organization-level permissions
- Sites - Site-level permissions