---
title: "Orleans.Lattice.Auth configuration"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.auth/configuration.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice.auth/configuration.md"
package: "Orleans.Lattice.Auth"
version: "9.9.0"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
bundle: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.auth/llms-full.txt"
---
# Orleans.Lattice.Auth configuration

Part of the [Auth documentation](README.md).

The package has one public options type, `LatticeAuthOptions`, which configures the policy store and decision engine: the closed-world fallback and tie-break rules, the durable per-key history retention applied to the reserved `sys-auth-policy` tree, the optional strict-consistency policy-epoch fence, and the optional audit sink and durable audit trail. It is bound through the `AddLatticeAuth` registration extension.

## `LatticeAuthOptions`

Configures how the decision engine compiles and evaluates rules, how policy history is retained, and how decisions are audited. Bind it through `AddLatticeAuth(configure)`, or layer an additional configuration delegate after registration with `ConfigureLatticeAuth(configure)`.

| Property | Type | Default | Meaning |
|---|---|---|---|
| `DefaultEffect` | `LatticeEffect` | `Deny` | The effect applied when no rule matches a request (the closed-world fallback). `Deny` is deny-by-default; set to `Allow` only for an allow-by-default deployment where rules exist purely to carve out denials. It never applies to a control-plane request - the reserved `sys-auth-*` and `sys-tenant-*` namespaces, the app-registry `sys-app-*` namespace, the tenant-administration capability ids, and a cluster-wide capability request on the `*` sentinel (such as `Telemetry` or `AppInstall`) - which is granted only by an explicit matched allow rule and is otherwise denied, even under `Allow`. |
| `BootstrapAdministrators` | `ISet<string>` | empty ordinal set | Subject ids allowed every operation on every tree - the control plane included, and every capability an `Admin` grant does not confer (for example `Telemetry`, `Replication`, `TreeLifecycle`, and `AppInstall`) - short-circuited before the decision engine and the strict epoch fence are consulted. Exists so a policy misconfiguration cannot lock every operator out of the authorization tree itself; keep it to the smallest set of break-glass identities. Entries must be non-null and non-empty. |
| `AccessAdministrationDelegationEnabled` | `bool` | `false` | Whether an access administrator may delegate access administration to another subject by authoring a rule on the reserved policy tree. Off by default: no rule may be scoped at the reserved `sys-auth-*` namespace, so the only access administrators are the `BootstrapAdministrators`. When `true`, an existing access administrator may author exactly one narrow rule shape - a whole-tree `Admin` rule on the `sys-auth-policy` tree - to delegate access administration to a chosen user or group; every other rule shape on the reserved namespace stays rejected fail-closed. Turning it off stops new delegations but does not revoke an existing grant (remove that rule to revoke). |
| `AllTreesGrantsEnabled` | `bool` | `false` | Whether a cluster-wide all-trees rule (scope `Tree:*`, the `LatticeScope.ClusterWideTreeId` sentinel) governs every ordinary application tree. Off by default: while off, authoring a data-plane `Tree:*` rule is rejected at the policy store with an `ArgumentException` that tells the operator to enable the tier first, so an inert data-plane wildcard grant can no longer be persisted silently (a pre-existing inert rule stays listed for visibility but never grants or denies until the tier is enabled). When `true`, the decision engine consults the `Tree:*` bucket for every non-system tree using a four-tier precedence: (1) an all-trees deny is returned outright; (2) else the target tree's own most-specific-wins verdict applies (a specific deny overrides a global allow); (3) else an all-trees allow grants access; (4) else `DefaultEffect`. The control-plane namespaces - the reserved `sys-auth-*` namespace, the tenant-registry `sys-tenant-*` namespace, the app-registry `sys-app-*` namespace, and the delegated tenant-administration capability namespace (`LatticeTenantAdminScope.TenantScopePrefix`, `_lattice_tenant_admin_`) - and a literal request targeting the sentinel `*` itself are never governed by the tier (fail-closed), and operation-bit separation is preserved so a data-plane grant never confers `Telemetry`. Telemetry and `AppInstall` `Tree:*` grants are unaffected by this flag - a wildcard rule carrying only those scopeless capabilities stays authorable, and in force, with the tier off. The authoring check tests only the data-plane mask (`LatticeAuthOperations.All`), so a `Tree:*` rule carrying only `Replication` and/or `TreeLifecycle` is also accepted with the tier off, but, unlike telemetry, it grants and denies nothing until the tier is enabled. Turning it off stops new all-trees evaluation but does not delete existing `Tree:*` rules (remove the rule to retire it). |
| `UserRuleBeatsGroupRuleAtEqualScope` | `bool` | `true` | When `true`, a rule whose subject is the requesting user is treated as more specific than a rule whose subject is one of the user's groups at the same scope, so the user-specific rule wins the tie (including a user-specific allow overriding a group-level deny at equal scope). When `false`, user and group rules are equally specific at equal scope, so the deny-overrides tie-break decides between them. |
| `HistoryRetentionMode` | `HistoryRetentionMode` | `MetadataOnly` | The retention mode for the durable per-key history captured on the `sys-auth-policy` tree. History is never disabled by default. |
| `HistoryRetentionWindow` | `TimeSpan?` | `null` | The age after which a policy history revision row expires, or `null` for no age bound. Must be strictly positive when supplied. |
| `EnableDurableHistoryView` | `bool` | `true` | Whether to create the durable per-key history materialised view over the `sys-auth-policy` tree so policy changes remain auditable beyond the source write-ahead-log window. |
| `StrictConsistencyTrees` | `ISet<string>?` | `null` | The set of tree ids opted into the optional strict-consistency policy-epoch fence. Empty / `null` is the eventual path: enforcement never consults the fence, so a deployment that does not opt in pays zero added cost and keeps last-writer-wins convergence. When a tree id is listed, a user write to that tree - a request carrying `Write`, `Delete`, `RangeDelete`, `CrdtApply`, `AtomicWrite`, `BulkLoad`, `Admin`, or `Restore` - is rejected if the caller stamped a required policy-epoch floor onto the ambient context (`LatticePolicyEpochFenceContext.RequireAtLeast`) and this cluster's locally compiled policy epoch has not yet caught up. Reads and internal / system-origin / replication-applied writes are never fenced. Entries must be non-null and non-empty. |
| `EnableAuditSink` | `bool` | `false` | Master switch for the audit sink seam. When `false`, a gated decision builds no decision event and dispatches to no audit sink, so auditing is strictly zero-cost on the hot path. Set to `true` to fan every admissible decision out to the registered sinks. Independent of the observability meter, whose counters and latency histogram are always available when an OpenTelemetry listener is attached. |
| `AuditVerbosity` | `LatticeAuthAuditVerbosity` | `DenyOnly` | Which decisions are dispatched to the audit sinks when `EnableAuditSink` is set. `DenyOnly` audits refusals only; `AllDecisions` audits every gated decision, allow and deny, at materially higher event volume. |
| `AuditSamplingRatio` | `double` | `1.0` | The fraction of admissible decisions (those passing the `AuditVerbosity` filter) actually dispatched to the audit sinks, in the inclusive range `0.0` to `1.0`. `1.0` audits every admissible decision; `0.0` suppresses all dispatch even while `EnableAuditSink` is set; `0.1` samples roughly one in ten. Sampling never affects the observability meter. |
| `EnableDurableAuditTrail` | `bool` | `false` | Whether to also append every dispatched decision event to the durable, append-only `sys-auth-audit` lattice tree. Opt-in and costs nothing until enabled. Requires `EnableAuditSink` to be set for any event to be produced. |
| `AuditTrailTimeToLive` | `TimeSpan?` | `null` | The time-to-live applied to each durable audit-trail row, or `null` for no age bound. Must be strictly positive when supplied. Only consulted when `EnableDurableAuditTrail` is set. |

## Discovering the effective posture

Both tier flags (`AllTreesGrantsEnabled` and `AccessAdministrationDelegationEnabled`) are opt-in and off by default, and a disabled tier is otherwise easy to miss - an all-trees grant is inert and a delegation grant is unauthorable. To make the deployment's opt-in state observable without inspecting configuration, the posture is surfaced on four read paths:

- **Start-up log.** `AddLatticeAuth` registers a hosted service that logs one informational line at silo start: `Lattice authorization posture: DefaultEffect=..., AllTreesGrantsEnabled=..., AccessAdministrationDelegationEnabled=...`. It is the first place an operator sees the effective posture.
- **`ILatticeAuthAdmin.ExplainAsync`.** The returned `AuthExplanation` carries a `Posture` (`AuthPolicyPosture`) reporting both flags, so an explain of a request that fell through to `DefaultEffect` shows whether a `Tree:*` rule would have applied had the tier been on.
- **`ILatticeAuthAdmin.EffectivePermissionsAsync`.** The returned `AuthEffectivePermissions` carries the same `Posture`, so a listing that includes an inert `Tree:*` rule also reports that the tier is off.
- **`ILatticeAuthAdmin.GetAccessModelAsync`.** The returned `AccessModelDescriptor` carries `AllTreesGrantsEnabled` and `AccessAdministrationDelegationEnabled`, which the Explorer's Access area renders as on/off entries in its access-posture banner, beside the authentication mode.

The `AuthPolicyPosture` record reports only the two opt-in tier flags; `DefaultEffect` is surfaced separately on `AuthExplanation`.
