Umbraco User Groups, Roles, and Permissions | OpsBlu Docs

Umbraco User Groups, Roles, and Permissions

Comprehensive guide to Umbraco Backoffice user groups, section access, content permissions, and custom role configuration

Umbraco uses a flexible user group and permissions system to control Backoffice access. This guide covers default user groups, section permissions, content-level permissions, custom group creation, and .NET-based permission management.

Understanding Umbraco Permissions Model

User Groups vs Members

User Groups (Backoffice):

  • Control access to Umbraco Backoffice (/umbraco)
  • Manage content, media, and settings
  • Assigned via Users section
  • This guide focuses on user groups

Member Groups (Front-end):

  • Control access to website content
  • Front-end user authentication
  • Separate permission system

Permission Levels

Umbraco permissions operate at multiple levels:

  1. Section Access - Which Backoffice sections user can access
  2. Content Permissions - What actions user can perform on content
  3. Node-Level Permissions - Which content nodes user can see/edit
  4. Document Type Permissions - Which content types user can create

Default User Groups

Administrators

Full access to all Backoffice features.

Section Access:

  • Content
  • Media
  • Settings
  • Packages
  • Users
  • Members
  • Forms
  • Translation

Content Permissions:

  • Browse Node (F)
  • Create (C)
  • Update (A)
  • Delete (D)
  • Publish (U)
  • Copy (O)
  • Move (M)
  • Sort (S)
  • Send to Publish (H)
  • Permissions (R)
  • Audit Trail (Z)
  • Culture and Hostnames (I)
  • Public Access (P)
  • Notifications (N)

Use Cases:

  • System administrators
  • Senior developers
  • Agency owners
  • Full CMS control needed

Editors

Content management without system settings access.

Section Access:

  • Content
  • Media
  • Forms (optional)

Content Permissions:

  • Browse Node (F)
  • Create (C)
  • Update (A)
  • Delete (D)
  • Publish (U)
  • Copy (O)
  • Move (M)
  • Sort (S)
  • Notifications (N)

Use Cases:

  • Content managers
  • Marketing teams
  • Editorial staff
  • Daily content operations

Writers

Content creation without publish rights.

Section Access:

  • Content
  • Media

Content Permissions:

  • Browse Node (F)
  • Create (C)
  • Update (A)
  • Send to Publish (H)

Use Cases:

  • Junior content creators
  • Contractors
  • Guest bloggers
  • Require approval before publishing

Translators

Multi-language content management.

Section Access:

  • Content (translation mode)
  • Translation

Content Permissions:

  • Browse Node (F)
  • Update (A)
  • Culture and Hostnames (I)

Use Cases:

  • Translation agencies
  • Multi-lingual content teams
  • Localization specialists

Sensitive Data

Access to forms and member data.

Section Access:

  • Members
  • Forms

Content Permissions:

  • Browse Node (F)

Use Cases:

  • Customer service
  • Data privacy officers
  • Form administrators
  • GDPR compliance teams

Content Permission Letters

Each permission represented by a letter code:

Code Permission Description
F Browse Node View content in tree
C Create Create new content
A Update Edit existing content
D Delete Delete content
U Publish Publish content
O Copy Duplicate content
M Move Move in content tree
S Sort Reorder child nodes
H Send to Publish Submit for approval
R Permissions Change permissions
Z Audit Trail View content history
I Culture and Hostnames Set culture/domains
P Public Access Set protection
N Notifications Manage notifications
K Rollback Restore previous versions

Creating Custom User Groups

Via Backoffice

  1. Navigate to Users section
  2. Click User Groups folder
  3. Click Create User Group
  4. Enter details:
    • Name: "Regional Editors"
    • Alias: regionalEditors (auto-generated)
    • Icon: Select appropriate icon
  5. Configure Section Access
  6. Set Default Permissions
  7. Set Start Nodes (optional)
  8. Click Save

Programmatically Create User Group

UserGroupService.cs:

using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;

namespace YourProject.Services
{
    public class CustomUserGroupService
    {
        private readonly IUserGroupService _userGroupService;
        private readonly IContentService _contentService;

        public CustomUserGroupService(
            IUserGroupService userGroupService,
            IContentService contentService)
        {
            _userGroupService = userGroupService;
            _contentService = contentService;
        }

        public IUserGroup CreateRegionalEditorGroup(int startNodeId)
        {
            // Create user group
            var userGroup = new UserGroup(0)
            {
                Name = "Regional Editors",
                Alias = "regionalEditors",
                Icon = "icon-users"
            };

            // Set section access
            userGroup.AddAllowedSection("content");
            userGroup.AddAllowedSection("media");

            // Set default permissions
            userGroup.Permissions = new[]
            {
                "F", // Browse
                "C", // Create
                "A", // Update
                "U", // Publish
                "O", // Copy
                "M", // Move
                "S"  // Sort
            };

            // Set start node
            if (startNodeId > 0)
            {
                var startNode = _contentService.GetById(startNodeId);
                if (startNode != null)
                {
                    userGroup.StartContentId = startNodeId;
                }
            }

            // Save user group
            _userGroupService.Save(userGroup);

            return userGroup;
        }
    }
}

Advanced Permission Configuration

Set Node-Specific Permissions

Programmatically:

public void SetNodePermissions(int nodeId, int userId, string[] permissions)
{
    var contentService = Services.ContentService;
    var userService = Services.UserService;

    var content = contentService.GetById(nodeId);
    var user = userService.GetUserById(userId);

    if (content != null && user != null)
    {
        var permissionSet = new EntityPermissionSet(
            nodeId,
            new EntityPermissionCollection(
                permissions.Select(p => new EntityPermission(
                    user.Groups.First().Id,
                    nodeId,
                    new[] { p }
                ))
            )
        );

        contentService.SetPermissions(permissionSet);
    }
}

Usage:

// Give user only Update permission on specific node
SetNodePermissions(
    nodeId: 1234,
    userId: 5,
    permissions: new[] { "A" } // Update only
);

Restrict by Document Type

Create document type filter:

using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;

public class DocumentTypePermissionHandler :
    INotificationHandler<ContentSavingNotification>
{
    private readonly IUserService _userService;

    public DocumentTypePermissionHandler(IUserService userService)
    {
        _userService = userService;
    }

    public void Handle(ContentSavingNotification notification)
    {
        var currentUser = _userService.GetUserById(notification.State["UserId"]);

        foreach (var content in notification.SavedEntities)
        {
            // Restrict "Product" document type to Administrators only
            if (content.ContentType.Alias == "product")
            {
                if (!currentUser.Groups.Any(g => g.Alias == "admin"))
                {
                    notification.CancelOperation(
                        new EventMessage(
                            "Access Denied",
                            "Only Administrators can create Products",
                            EventMessageType.Error
                        )
                    );
                }
            }
        }
    }
}

Implement Custom Section

Create custom section for specific user group:

using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Sections;

namespace YourProject.Sections
{
    [Weight(40)]
    public class ReportsSection : ISection
    {
        public string Alias => "reports";
        public string Name => "Reports";
    }

    public class ReportsSectionComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.Sections().Append<ReportsSection>();
        }
    }
}

Assign to user group:

var userGroup = _userGroupService.GetUserGroupByAlias("administrators");
userGroup.AddAllowedSection("reports");
_userGroupService.Save(userGroup);

Start Nodes (Content Tree Restrictions)

Set Start Nodes via Backoffice

  1. Navigate to Users section
  2. Click User Groups
  3. Select user group to edit
  4. Scroll to Start Nodes
  5. Click Choose under Content
  6. Select root node for this group
  7. Click Save

Example: Regional editors for North America only see /en/regions/north-america/ node and below.

Set Start Nodes Programmatically

public void SetStartNode(string userGroupAlias, int startNodeId)
{
    var userGroup = _userGroupService.GetUserGroupByAlias(userGroupAlias);

    if (userGroup != null)
    {
        userGroup.StartContentId = startNodeId;
        userGroup.StartMediaId = null; // Full media access

        _userGroupService.Save(userGroup);
    }
}

Set Media Start Nodes

public void SetMediaStartNode(string userGroupAlias, int mediaFolderId)
{
    var userGroup = _userGroupService.GetUserGroupByAlias(userGroupAlias);

    if (userGroup != null)
    {
        userGroup.StartMediaId = mediaFolderId;
        _userGroupService.Save(userGroup);
    }
}

Permission Checking in Code

Check User Permissions

using Umbraco.Cms.Core.Services;

public class PermissionChecker
{
    private readonly IUserService _userService;
    private readonly IContentService _contentService;

    public PermissionChecker(IUserService userService, IContentService contentService)
    {
        _userService = userService;
        _contentService = contentService;
    }

    public bool UserCanPublish(int userId, int nodeId)
    {
        var user = _userService.GetUserById(userId);
        var content = _contentService.GetById(nodeId);

        if (user == null || content == null)
            return false;

        var permissions = _userService.GetPermissions(user, nodeId);

        return permissions.Any(p => p.AssignedPermissions.Contains("U"));
    }

    public bool UserHasSection(int userId, string sectionAlias)
    {
        var user = _userService.GetUserById(userId);

        return user?.Groups.Any(g => g.AllowedSections.Contains(sectionAlias)) ?? false;
    }
}

Enforce Permissions in Controller

using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Web.BackOffice.Controllers;

namespace YourProject.Controllers
{
    [Authorize(Policy = "BackOfficeAccess")]
    public class CustomApiController : UmbracoAuthorizedApiController
    {
        private readonly PermissionChecker _permissionChecker;

        public CustomApiController(PermissionChecker permissionChecker)
        {
            _permissionChecker = permissionChecker;
        }

        [HttpPost]
        public IActionResult PublishContent(int nodeId)
        {
            var currentUser = User.Identity.GetUserId<int>();

            if (!_permissionChecker.UserCanPublish(currentUser, nodeId))
            {
                return Forbid("You do not have permission to publish this content");
            }

            // Publish content
            var content = Services.ContentService.GetById(nodeId);
            Services.ContentService.SaveAndPublish(content);

            return Ok();
        }
    }
}

Workflow and Approval Process

Configure Send to Publish Workflow

For Writers (no publish rights):

  1. Writer creates/edits content
  2. Clicks Save
  3. Clicks Request Publish
  4. Notification sent to Editors
  5. Editor reviews and publishes

Notification Handler:

using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;

public class SendToPublishNotificationHandler :
    INotificationHandler<ContentSendToPublishNotification>
{
    private readonly IEmailSender _emailSender;
    private readonly IUserService _userService;

    public SendToPublishNotificationHandler(
        IEmailSender emailSender,
        IUserService userService)
    {
        _emailSender = emailSender;
        _userService = userService;
    }

    public async Task Handle(
        ContentSendToPublishNotification notification,
        CancellationToken cancellationToken)
    {
        var content = notification.Entity;
        var sender = notification.State["User"];

        // Get all Editors
        var editors = _userService.GetAll(0, int.MaxValue, out long total)
            .Where(u => u.Groups.Any(g => g.Alias == "editors"));

        foreach (var editor in editors)
        {
            await _emailSender.SendAsync(new EmailMessage(
                editor.Email,
                "Content Awaiting Approval",
                $"Content '{content.Name}' is awaiting your approval.\n\n" +
                $"Submitted by: {sender}\n" +
                $"View: {GetBackofficeUrl(content.Id)}",
                isBodyHtml: false
            ), emailType: "ContentApproval");
        }
    }
}

Custom Permission Examples

Example: Regional Content Manager

Requirements:

  • Access only to specific region (e.g., North America)
  • Can create, edit, publish content in region
  • Can upload media
  • Cannot access Settings or Users

Implementation:

public void CreateRegionalManagerGroup(int regionNodeId)
{
    var userGroup = new UserGroup(0)
    {
        Name = "North America Managers",
        Alias = "naManagers",
        Icon = "icon-globe"
    };

    // Sections
    userGroup.AddAllowedSection("content");
    userGroup.AddAllowedSection("media");

    // Permissions
    userGroup.Permissions = new[] { "F", "C", "A", "U", "O", "M", "S", "N" };

    // Start node (North America region)
    userGroup.StartContentId = regionNodeId;

    _userGroupService.Save(userGroup);
}

Example: Form Administrator

Requirements:

  • Access to Forms section only
  • Can view/export form submissions
  • No content access

Implementation:

public void CreateFormAdminGroup()
{
    var userGroup = new UserGroup(0)
    {
        Name = "Form Administrators",
        Alias = "formAdmins",
        Icon = "icon-list"
    };

    // Only Forms section
    userGroup.AddAllowedSection("forms");

    // No content permissions needed
    userGroup.Permissions = new string[] { };

    _userGroupService.Save(userGroup);
}

Example: Read-Only Reviewer

Requirements:

  • Can view all content
  • Cannot create, edit, or publish
  • Used for stakeholder reviews

Implementation:

public void CreateReviewerGroup()
{
    var userGroup = new UserGroup(0)
    {
        Name = "Reviewers",
        Alias = "reviewers",
        Icon = "icon-eye"
    };

    userGroup.AddAllowedSection("content");

    // Browse only
    userGroup.Permissions = new[] { "F" };

    _userGroupService.Save(userGroup);
}

Security Best Practices

Principle of Least Privilege

  • Grant minimum access needed for role
  • Review permissions quarterly
  • Document permission changes
  • Use specific user groups instead of broad access

Regular Audits

public class PermissionAuditService
{
    public void AuditUserGroups()
    {
        var userGroups = _userGroupService.GetAll();

        foreach (var group in userGroups)
        {
            Console.WriteLine($"Group: {group.Name}");
            Console.WriteLine($"  Sections: {string.Join(", ", group.AllowedSections)}");
            Console.WriteLine($"  Permissions: {string.Join(", ", group.Permissions)}");
            Console.WriteLine($"  Start Node: {group.StartContentId}");

            var users = _userService.GetAll(0, int.MaxValue, out long total)
                .Where(u => u.Groups.Any(g => g.Id == group.Id));

            Console.WriteLine($"  Users: {users.Count()}");
            Console.WriteLine();
        }
    }
}

Separation of Duties

  • Don't assign same user to conflicting groups
  • Separate content creation from publishing (for sensitive content)
  • Separate user management from content management
  • Use workflow for high-value content

Common Issues

User Cannot See Content

Cause: Start nodes restrict visibility Solution: Check user group start nodes, adjust if needed

User Cannot Publish

Cause: Missing "Publish" (U) permission Solution: Add "U" permission to user group or use "Send to Publish" workflow

Changes Not Taking Effect

Cause: User needs to log out and back in Solution: Inform user to refresh session or restart browser

Next Steps