Skip to main content

ACL administration

client.Server exposes typed ACL inspection and administration. Each ordinary method runs on one execution node. ACL configuration and logs belong to that node; changing a Cluster primary does not configure the other members.

await using var client = await RespireClient.ConnectAsync(new RespireOptions
{
Endpoints = [new("localhost", 6379)],
AllowAdmin = true,
});

await client.Server.AclSetUserAsync("reader",
["reset", "on", ">a-secret-from-your-secret-store", "~orders:*", "+get"]);
RespireAclUser? user = await client.Server.AclGetUserAsync("reader");
RespireAclDryRunResult check = await client.Server.AclDryRunAsync(
"reader", RespireCommands.String.GET, ["orders:42"]);
if (!check.IsAllowed) Console.WriteLine(check.DenialReason);

AclSetUserAsync, AclDeleteUsersAsync, and AclLogResetAsync, including their all-node variants, require AllowAdmin = true before network I/O. Inspection methods follow the existing read-only Server convention and do not require this client option. The server still enforces the authenticated user's ACL permissions for every command.

Rules are separate, ordered RespireValue arguments. Updates are additive unless a rule such as reset changes that behavior. Redis validates rule syntax; malformed or unsupported rules surface its server error without client-side rewriting. An empty rule list is valid; an empty delete-user list is rejected. Usernames, rules, categories, and dry-run arguments are snapshotted before asynchronous work. They are not routing keys and never receive a client key prefix. Byte inputs retain their bytes. Compound dry-run descriptors such as "CLIENT LIST" expand into command tokens; each supplied argument remains one token. DRYRUN checks permissions without executing the command. Denials return IsAllowed = false and the server's message. Missing users, invalid commands, and server errors throw normally. AclGetUserAsync returns null for a missing user.

Owned results and versions​

WHOAMI, LIST, GETUSER, SETUSER, DELUSER, CAT, and LOG require Redis 6.0 or later. DRYRUN and selectors require Redis 7.0 or later. Unsupported commands surface server errors; the client does not silently emulate security operations.

WHOAMI returns byte[]; LIST returns byte[][]. User and selector models retain binary key/channel rules in RespireAclPatterns. Redis 6.x supplies LegacyPatterns; Redis 7+ supplies RuleExpression. Exactly one is present, and the client does not split the expression on spaces. Channel rules are absent before Redis 6.2. Flags, password hashes, and command expressions are strings. Unknown structured fields are preserved in AdditionalFields as recursively copied RespireResult values. These results own GC storage; disposal is optional and invalidates their element views. The other result models need no disposal and remain valid after the client is disposed.

AclCategoriesAsync() lists categories; supplying a category lists its commands. AclLogAsync() uses the server's default count, and an explicit nonnegative count limits returned entries. Zero returns an empty result without resetting the log. Entries remain newest first. AclLogResetAsync() explicitly clears the log. Log object, username, and client-info fields retain bytes. Entry IDs and Unix millisecond timestamps are nullable because Redis added them in 7.2. Unknown reason/context values remain strings instead of being rejected by an enum.

See Redis's GETUSER, SETUSER, LOG, and DRYRUN references for rule semantics.

Explicit operations across nodes​

Every ACL method has an OnAllNodesAsync counterpart. These discover Cluster members, including replicas, and return RespireServerResult<T>[] with endpoint provenance. Standalone returns one result. Discovery requires permission to inspect CLUSTER NODES. WHOAMI reports the identity authenticated on the connection used for that node.

var results = await redis.Server.AclGetUserOnAllNodesAsync("reader");
foreach (var result in results)
{
if (result.IsSuccess)
Console.WriteLine($"{result.Endpoint}: user present = {result.Value is not null}");
else
Console.WriteLine($"{result.Endpoint}: {result.Error!.Message}");
}

Inspect every result. All-node mutations can partly succeed and are not atomic or rolled back. Cancellation during discovery throws; after discovery it is attributed to affected nodes while completed successes remain available. A successful SETUSER or LOG RESET node result has Value = true; DELUSER reports the count on each node. These methods do not save an ACL file or guarantee future nodes inherit configuration.

ACL responses can contain password hashes and security details. Do not log rule arguments or credentials. Respire records operation names rather than adding argument logging; server error messages remain intact for diagnosis.

The 18 methods extend IServerCommands. External implementations, decorators, and mocks must implement or forward them. These APIs are immediate Server operations; they do not add ACL methods to batches or transactions.