Skip to content
RustPluginGenerator

OnGroupCreated

OnGroupCreated is called by Oxide right after a new group has been added to the permission data, giving plugins the group's name, title and rank. It fires from Permission.CreateGroup and only when a group was actually created.

Signature
void OnGroupCreated(string groupName, string groupTitle, int groupRank)

Parameters

Hook parameters
ParameterTypeDescription
groupNamestringThe internal name of the newly created group, e.g. the key stored in the groups data file. This is what you pass to other permission API calls.
groupTitlestringThe display title assigned to the group when it was created. May be empty if the caller passed no title.
groupRankintThe rank integer the group was created with. Higher numbers generally sort above lower ones in Oxide's group listings.

Return value

The return value is ignored. Permission.CreateGroup calls the hook for its side effects only and then returns true regardless of what any plugin returned.

How it works

This hook is raised by Oxide's own permission system, not by a patched game method. Permission.CreateGroup first checks whether a group with that name already exists or the name is empty; if either is true it returns false and no hook fires. Otherwise it writes the new GroupData (title and rank) into the groups table and then calls OnGroupCreated(groupName, groupTitle, groupRank) before returning true.

Because the call happens after the data is already stored, the group is fully usable inside the hook: permission.GroupExists, permission.GetGroupTitle and grant calls all work. This makes the hook a reliable place to seed default permissions, attach metadata in your own data file, or log administrative activity.

Groups can be created from the server console (oxide.group add), from RCON, or by another plugin calling permission.CreateGroup. All three paths reach the same hook. Carbon loads Oxide plugins and raises the same hook, so code written against it works on both frameworks.

Narrowing by parameter type is not useful here: all three arguments are strings or an int, and every call carries the same shape.

Example plugin: Seed default permissions for staff groups on creation

GroupCreatedDefaults.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Group Created Defaults", "RustPluginGenerator", "1.0.0")]
    [Description("Grants a configured set of permissions to permission groups when they are created")]
    public class GroupCreatedDefaults : RustPlugin
    {
        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Default permissions per group (lowercase group name -> permission list)")]
            public Dictionary<string, List<string>> GroupDefaults = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase)
            {
                ["admin"] = new List<string> { "groupcreateddefaults.admin" },
                ["moderator"] = new List<string>()
            };
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, using defaults");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Seeded"] = "Group '{0}' created with rank {1}; granted {2} default permission(s)"
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);

        private void OnGroupCreated(string groupName, string groupTitle, int groupRank)
        {
            if (string.IsNullOrEmpty(groupName) || config?.GroupDefaults == null) return;
            if (!config.GroupDefaults.TryGetValue(groupName, out List<string> permissions) || permissions == null) return;

            int granted = 0;
            foreach (string perm in permissions)
            {
                if (string.IsNullOrEmpty(perm)) continue;
                if (permission.GroupHasPermission(groupName, perm)) continue;
                permission.GrantGroupPermission(groupName, perm, this);
                granted++;
            }

            if (granted > 0)
            {
                Puts(Msg("Seeded", null, groupName, groupRank, granted));
            }
        }
    }
}

The plugin watches for newly created permission groups and grants a configurable set of default permissions to any group whose name appears in the config, for example admin, moderator or vip.

On OnGroupCreated it looks up the group name case-insensitively in the configured defaults. If no entry matches, it returns quietly. Otherwise it loops over the permission list and calls permission.GrantGroupPermission for each one that the group does not already hold, then logs a short summary to the server console with Puts. Group creation is a rare administrative action, so console output here does not spam. The config is validated on load so an empty or broken file falls back to sensible defaults.

Common use cases

  • Apply staff permission templates

    Grant a fixed permission set to any newly created group named admin or moderator so a fresh server or wiped data file is set up correctly on the first group add.

  • Audit group creation

    Record the group name, title, rank and timestamp into your own data file in oxide/data so admins can later review who added which groups.

  • Sync groups to an external system

    Queue a notification for your own in-game staff UI or write a display name for the group into a plugin-owned table so other plugins can render it.

Pitfalls

  • Does not fire for pre-existing groups

    If the group name is already taken or empty, Permission.CreateGroup returns false early and the hook never runs. Do not rely on it to migrate groups that already exist in the data file.

  • Group name, not title, is the identifier

    Grant and query calls in the permission API use groupName. The title is just a display string and can be changed later with OnGroupTitleSet, which will not re-fire this hook.

  • Avoid loops that call CreateGroup again

    If your handler itself calls permission.CreateGroup for another name, expect a nested OnGroupCreated call. Guard against recursion if you generate derived group names.

Build a plugin with OnGroupCreated

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Apply staff permission templates using the OnGroupCreated hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnGroupCreated

Generate