2 - Granting, Checking and Revoking

The Actual Work: Grant, Check, Revoke

Once a store exists (see 1 - Setting Up A Permission Store), everything is done against a requester ID (the identifier XRUIOS.Manager issued to the app) and a permission name like "Edit Camera Footage".

Permissions are integer levels, not just on/off. A grant stores a number; a check asks "is the stored number at least requiredLevel?" This lets you model tiers (e.g. 1 = view, 5 = edit, 10 = delete) on a single permission name.

var requester = managerIssuedRequesterId; // SecureData from XRUIOS.Manager
var permName  = "Edit Camera Footage".ToSecureData();
The requester comes from the function's own inputs — the caller must point at or provide the ID. The permission name can be whatever you pass here, whether that's the function's own name or a friendlier label like "Edit Camera Footage". The auto-gating layer in 3 - Auto-Gating Functions (The Attribute) fills both of these in for you.

Grant (or overwrite) a permission

The permission value is an int, wrapped in SecureData as its bytes:

var level = new SecureData(BitConverter.GetBytes(5)); // grant at level 5

await handler.HandlePermission(saveDir, permClass, permName, requester, level, appKey);

HandlePermission is an upsert, AKA if the requester doesn't exist yet it's added; if the permission already exists it's overwritten. After it writes, it refreshes the cache with the value it actually wrote (see 1 - How Caching and Rate Limiting Work), so the next check sees the new number immediately.


Check a permission

bool canEdit = await handler.CheckPermission(
    saveDir, permClass, permName, requester, appKey,
    requiredLevel: 5);
  • Stored level >= requiredLevel → true.
  • Requester or permission absent → false.
  • Store missing / wrong key / corrupted → false (fail closed), and the error is pushed to Handler.OnStoreError so you can tell a real denial apart from a broken store.
requiredLevel defaults to 0. Calling CheckPermission(...) with no level asks "do they have this permission at all (>= 0)?"

The important part: because the cache stores the value, checking the same permission at a higher level later is compared honestly. A true at level 3 can not be replayed as a true at level 10.


Change a permission

ChangePermission is a thin, clearly-named wrapper over `HandlePermission; it reads better at call sites where you're deliberately downgrading/upgrading:

var newLevel = new SecureData(BitConverter.GetBytes(1)); // drop to level 1

await handler.ChangePermission(saveDir, permClass, permName, requester, appKey, newLevel);

The next CheckPermission reflects the new value right away — there's no stale "granted" left in the cache.


Remove a single permission

await handler.RemovePermission(saveDir, permClass, permName, requester, appKey);

Throws KeyNotFoundException if the requester or that specific permission doesn't exist, and evicts just that one cache entry.


Remove a requester entirely

Drops the app/requester and all its permissions in one go:

await handler.RemoveRequester(saveDir, permClass, requester, appKey);
RemoveRequester does not take a permission name — it removes the whole requester. (Older code took an unused permission-name argument; it's gone.) It also precisely evicts every cache entry belonging to that requester, not the whole cache.

Quick reference

Call Effect
SetupPermFile Create the store (once)
PermissionFileExists Does the store exist?
HandlePermission Grant / overwrite a permission (upsert)
ChangePermission Same as above, named for intent
CheckPermission Is requester allowed at requiredLevel?
RemovePermission Remove one permission from one requester
RemoveRequester Remove a requester and all its permissions