OnGroupPermissionRevoked
OnGroupPermissionRevoked is called after Oxide removes a permission from a permission group. It fires only when the permission was actually present on the group and the removal succeeded.
void OnGroupPermissionRevoked(string groupName, string permission)Parameters
| Parameter | Type | Description |
|---|---|---|
groupName | string | Name of the Oxide permission group the permission was removed from, as passed to permission.RevokeGroupPermission. |
permission | string | Full permission string that was revoked, e.g. `myplugin.use`; it is already gone from the group when the hook runs. |
Return value
The return value is ignored. This is a notification hook and its original method returns void, so returning null or any value changes nothing in Oxide's permission handling.
How it works
The hook fires from Permission.RevokeGroupPermission, after the internal group data has dropped the permission entry. If the permission was not on the group, the method returns early and the hook never runs, so you can treat every call as a confirmed removal. It also fires for the implicit wildcard entry (*) when you revoke it.
Both parameters are plain strings. groupName is the group that lost the permission, and permission is the exact permission string that was removed. Use them to mirror the change into your own storage, invalidate caches that map groups to permissions, or log administrative changes for later review.
This runs on every call to permission.RevokeGroupPermission, including calls made by other plugins, console commands such as oxide.group revoke, and RCON. There is no player argument and no initiator, so you cannot tell from the hook alone who triggered it; if you need that, pair it with a command hook or track changes your own plugin performs.
Because the hook is synchronous and runs inside the permission call, keep the handler cheap. Do not write data files on every call if the permission tree changes in bulk; batch it with a timer or a dirty flag instead.
Example plugin: Audit group permission changes to a data file
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Group Perm Audit", "RustPluginGenerator", "1.0.0")]
[Description("Records revoked group permissions to a rolling log in oxide/data.")]
public class GroupPermAudit : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Group prefix to audit (empty = all groups)")]
public string GroupPrefix = "";
[JsonProperty("Max entries")]
public int MaxEntries = 200;
}
private class AuditEntry
{
[JsonProperty("Group")]
public string Group;
[JsonProperty("Permission")]
public string Permission;
[JsonProperty("Revoked at (UTC)")]
public string When;
}
private const string PermLog = "grouppermaudit.log";
private const string DataName = "GroupPermAudit.Log";
private PluginConfig config;
private List<AuditEntry> entries = new List<AuditEntry>();
private Timer flushTimer;
private bool dirty;
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);
private void Init()
{
permission.RegisterPermission(PermLog, this);
entries = Interface.Oxide.DataFileSystem.ReadObject<List<AuditEntry>>(DataName) ?? new List<AuditEntry>();
}
private void Unload()
{
flushTimer?.Destroy();
SaveLog();
}
private void OnGroupPermissionRevoked(string groupName, string permissionName)
{
if (string.IsNullOrEmpty(groupName) || string.IsNullOrEmpty(permissionName)) return;
if (!string.IsNullOrEmpty(config.GroupPrefix) && !groupName.StartsWith(config.GroupPrefix, StringComparison.OrdinalIgnoreCase)) return;
entries.Add(new AuditEntry
{
Group = groupName,
Permission = permissionName,
When = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")
});
dirty = true;
if (flushTimer == null)
flushTimer = timer.Once(5f, Flush);
}
private void Flush()
{
flushTimer = null;
if (!dirty) return;
SaveLog();
}
private void SaveLog()
{
dirty = false;
if (config.MaxEntries > 0 && entries.Count > config.MaxEntries)
entries.RemoveRange(0, entries.Count - config.MaxEntries);
Interface.Oxide.DataFileSystem.WriteObject(DataName, entries);
}
[ConsoleCommand(PermLog)]
private void CmdLog(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.IsAdmin && !permission.UserHasPermission(arg.Player().UserIDString, PermLog))
{
arg.ReplyWith("You do not have permission to use this command.");
return;
}
if (entries.Count == 0)
{
arg.ReplyWith("No revoked group permissions have been recorded.");
return;
}
int count = Math.Min(arg.GetInt(0, 10), entries.Count);
arg.ReplyWith($"Last {count} revoked group permissions:");
foreach (var entry in entries.Skip(entries.Count - count))
arg.ReplyWith($"{entry.When} | {entry.Group} | {entry.Permission}");
}
}
}The plugin records every permission.RevokeGroupPermission call that passes its filter and appends it to a rolling log stored in oxide/data. OnGroupPermissionRevoked checks whether the group name starts with the configured audit prefix, then stores the group, permission and a UTC timestamp, trimming the oldest entries once Max entries is reached. The log is only written after a short debounce timer fires, so a bulk revoke of dozens of permissions from one command produces a single disk write. On unload the pending timer is flushed and the file is saved. The grouppermaudit.log console command lets an admin print the most recent entries from the server console or in-game.
Common use cases
Mirror permissions into an external system
Keep a local snapshot of each group's permissions in oxide/data so another tool or plugin can read it without calling into Oxide's permission API.
Detect accidental privilege removal
Compare the revoked permission against a critical allow-list and alert admins when an important permission is stripped from a staff group.
Audit trail for staff groups
Record who lost what and when for moderation review by combining the hook with a command hook that records the initiator of the revoke.
Pitfalls
Not fired when the permission is absent
Oxide returns early when the group does not hold the permission, so do not rely on this hook to observe every attempted revoke call.
No initiator information
The hook only receives group and permission strings. Calls from other plugins, console and RCON look identical, so track the source separately if you need to attribute changes.
Bulk changes cause many calls
Revoking a wildcard or running a script that revokes many permissions fires the hook once per entry. Debounce disk writes instead of saving on every invocation.
Build a plugin with OnGroupPermissionRevoked
Describe what should happen and get a compiled plugin that uses this hook.
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 OnGroupPermissionRevoked
Generate