---
title: "Orleans.Lattice.Membership configuration"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.membership/configuration.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice.membership/configuration.md"
package: "Orleans.Lattice.Membership"
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.membership/llms-full.txt"
---
# Orleans.Lattice.Membership configuration

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

The package has four public options types. `LatticeMembershipOptions` and `LatticeIdentityDirectoryOptions` are both bound by the `AddLatticeMembership` registration extension (the directory options via standard `services.Configure<LatticeIdentityDirectoryOptions>(...)`). `JwtAuthenticatorOptions` is bound per issuer by `AddLatticeJwtAuthenticator`, and `StaticIdentityDirectoryOptions` is bound by `AddStaticIdentityDirectory`.

## `LatticeMembershipOptions`

The token-vs-directory group merge policy, the per-silo resolution-cache lifetime, and the durable per-key history retention applied to the `sys-membership-*` trees. Bind it through `AddLatticeMembership(configure)`, or layer an additional configuration delegate after registration with `ConfigureLatticeMembership(configure)`. The three history settings are applied by a one-time bootstrap that each silo runs before its first membership-directory write (upserting or removing a group, or adding or removing a member); a silo that has already bootstrapped does not re-apply later changes to them.

| Property | Type | Default | Meaning |
|---|---|---|---|
| `GroupMergeMode` | `SubjectGroupMergeMode` | `Union` | How token-asserted and directory-derived groups combine into the resolved subject: whether resolution reads the directory closure at all (skipped under `TokenOnly`) and re-expands token and claim-projected seed groups through it, and how the default subject mapper merges the two sources. See [Group merge mode](README.md#group-merge-mode). Must be a defined `SubjectGroupMergeMode` value. |
| `ResolutionCacheTtl` | `TimeSpan` | `5 minutes` | The maximum lifetime of a per-silo resolution-cache entry. A resolved subject is additionally never served past the inbound token's expiry, so the effective bound is the minimum of this value and the token's remaining validity. `TimeSpan.Zero` disables caching (every resolution re-validates). Must not be negative. Only a resolved (non-anonymous) subject is cached, at most 4,096 per silo, and the whole cache is flushed whenever this silo observes a `sys-membership-*` mutation. The mutation observer runs on the silo that commits the write, so in a multi-silo cluster another silo can keep serving an entry resolved before a membership change until that entry expires. |
| `HistoryRetentionMode` | `HistoryRetentionMode` | `MetadataOnly` | The retention mode for the durable per-key history captured on the `sys-membership-*` trees. History is never disabled by default. Must be a defined `HistoryRetentionMode` value. |
| `HistoryRetentionWindow` | `TimeSpan?` | `null` | The age after which a membership 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 each `sys-membership-*` tree so membership changes remain auditable beyond the source write-ahead-log window. |
| `ClaimToGroups` | `Func<IReadOnlyDictionary<string, string>, IEnumerable<string>>?` | `null` | An optional projection from a principal's claims to additional group ids, applied by the default subject mapper. `null` adds no claim-derived groups. |

## `LatticeIdentityDirectoryOptions`

Provider-neutral bounds for the identity-directory seam: the default and maximum search page sizes, and whether a supplied id must resolve before an administrative create path records it. Configured through `AddLatticeMembership` (`services.Configure<LatticeIdentityDirectoryOptions>(...)`).

| Property | Type | Default | Meaning |
|---|---|---|---|
| `DefaultPageSize` | `int` | `25` | The page size a provider applies when a directory search query requests none (its page size is `0`). Must be strictly positive and no greater than `MaxPageSize`. |
| `MaxPageSize` | `int` | `100` | The upper bound a provider clamps a requested search page size to. Must be strictly positive. |
| `ValidationRequired` | `bool` | `false` | Whether a supplied principal id must resolve to an existing directory principal before an administrative create path records it: a group upsert or member add through `ILatticeAuthAdmin`, or a tenant admin subject (see [Fail-closed create validation](identity-directory-providers.md#fail-closed-create-validation-validationrequired)). The subject of an authorization rule is not checked. No validation runs while the no-op `NullIdentityDirectory` is active. `false` accepts ids without validation, matching the behaviour of the no-op null directory. |

## `JwtAuthenticatorOptions`

Configuration for a single JWT credential authenticator instance: the issuer it owns, the audiences and signing keys it trusts, and the claim types it maps into a principal. One authenticator is registered per issuer, so a silo can trust several identity providers at once. Bind it through `AddLatticeJwtAuthenticator(configure)`.

| Property | Type | Default | Meaning |
|---|---|---|---|
| `Issuer` | `string` | `""` (empty) | The token issuer this authenticator owns (the JWT `iss` claim). Used both to validate the token and to select this authenticator when the credential's scheme / issuer hint matches. Must be set. |
| `SchemeHint` | `string?` | `null` | Optional scheme hint (for example `Bearer` or a short provider name). When set, a credential whose scheme equals this value (compared case-insensitively) selects this authenticator without the token being parsed. The token's `iss` claim is read only for a credential that carries no scheme: a credential with any other scheme is selected only when that scheme equals `Issuer` (compared ordinally), and is otherwise declined without its token being read. The credential bridges in the gRPC and MCP facade bindings stamp their configured `CredentialScheme` (`Bearer` by default) on every credential they bridge, so an authenticator that must serve those calls sets this hint to that scheme. A matching hint claims the credential whatever its issuer: a token from another issuer presented under the hinted scheme fails validation here and resolves to the anonymous subject instead of reaching a later authenticator. |
| `Audiences` | `IList<string>` | empty list | The audiences this authenticator accepts (the JWT `aud` claim). Must be non-empty when `ValidateAudience` is `true` (construction fails closed otherwise, so audience validation is never silently disabled); the check is skipped when an explicit `ValidationParameters` is supplied. Populate the collection in place. |
| `SigningKeys` | `IList<SecurityKey>` | empty list | The signing keys trusted for token-signature validation. Ignored when an explicit `ValidationParameters` is supplied or a subclass overrides key resolution (for example via JWKS discovery). Populate the collection in place. |
| `Algorithms` | `IList<string>` | empty list | The token signature algorithms accepted (the JWT header `alg`), pinned via `ValidAlgorithms`. An explicit pin is authoritative and never widened. When empty, the allow-list is derived from the families of the configured `SigningKeys` (an RSA-only or EC-only key set accepts only that family's algorithms, a symmetric-only set only the HMAC algorithms), so a token cannot be verified against a key of the wrong family; acceptance is left unrestricted only when no family can be established (no keys, a mixed symmetric/asymmetric set, or an unrecognised key type), and `RequireAlgorithmPin` decides that case. Populate it (for example `["RS256"]`) to pin explicitly as a defense-in-depth measure against algorithm-confusion attacks. Populate the collection in place. |
| `RequireAlgorithmPin` | `bool` | `false` | Whether to refuse every token when no algorithm allow-list can be established - neither pinned in `Algorithms` nor derivable from the signing keys - instead of leaving acceptance unrestricted. `true` installs a deny-all algorithm validator, failing closed against algorithm confusion. The shipped Entra and OIDC authenticators turn it on. |
| `SubjectClaimTypes` | `IList<string>` | `["sub", "nameid"]` | The claim types consulted, in order, to resolve the subject id. The first present claim wins, falling back to the standard name-identifier claim when none is present. A validated token that yields no subject id, or one equal to the reserved anonymous or system subject id, resolves to the anonymous subject rather than an authorized principal. Populate the collection in place. |
| `GroupClaimTypes` | `IList<string>` | `["groups", "roles", "role"]` | The claim types whose values are collected as token-asserted group ids. Populate the collection in place. |
| `ValidateAudience` | `bool` | `true` | Whether to validate the token audience. When `true`, at least one entry in `Audiences` is required or construction throws (audience validation is never silently disabled), unless an explicit `ValidationParameters` is supplied; set to `false` to accept any audience explicitly. |
| `ValidateLifetime` | `bool` | `true` | Whether to validate the token lifetime (`exp` / `nbf`). |
| `ClockSkew` | `TimeSpan` | `5 minutes` | The permitted clock skew during lifetime validation. |
| `ValidationParameters` | `TokenValidationParameters?` | `null` | An explicit validation-parameters override. When set it replaces the parameters built from the validation fields above (`Audiences`, `SigningKeys`, `Algorithms`, `ValidateAudience`, `ValidateLifetime`, `ClockSkew`, and the issuer check), though `Issuer` must still be set because it selects this authenticator and is stamped on the resolved principal. One restriction is still applied on top: when the override carries no algorithm restriction of its own (no `AlgorithmValidator` and no non-empty `ValidAlgorithms`), the allow-list is derived from the override's statically-visible signing keys, and when none can be derived (for the reasons listed under `Algorithms`, or because the override resolves keys through a key resolver or configuration manager) `RequireAlgorithmPin` decides whether every algorithm is refused. Provided as an extension point for OIDC / JWKS discovery and signing-key rotation. |

## `StaticIdentityDirectoryOptions`

Configures the in-memory roster surfaced by the static identity directory: an explicitly-declared set of known principals for deployments with no queryable external directory. Bind it through `AddStaticIdentityDirectory(configure)`. Populate it via `AddUser` / `AddGroup`, or discover the deployed Basic user ids via `AddUsersFromEnvironment`.

### Constants

| Constant | Type | Value | Meaning |
|---|---|---|---|
| `DefaultEnvironmentVariablePrefix` | `string` | `"LATTICE_STATE_USER_"` | The default environment-variable prefix under which the reference Basic authorizer stores each user's credential, so `AddUsersFromEnvironment` discovers the same user set. User `alice` is provisioned as `LATTICE_STATE_USER_alice`. |

### Properties

| Property | Type | Default | Meaning |
|---|---|---|---|
| `Principals` | `IList<DirectoryPrincipal>` | empty list | The declared roster of known principals, in declaration order. The static directory takes an immutable snapshot at construction; later mutation has no effect on an already-built provider. When the same id is declared more than once the last entry wins. Populate via `AddUser` / `AddGroup` / `AddUsersFromEnvironment` rather than editing the list directly. |

### Methods

Each method appends to `Principals` and returns the same options instance for chaining.

| Method | Meaning |
|---|---|
| `AddUser(string id, string? displayName = null)` | Adds a user principal. `id` must not be `null` or empty; `displayName` defaults to `id`. |
| `AddGroup(string id, string? displayName = null)` | Adds a group principal, with the same rules as `AddUser`. |
| `AddUsersFromEnvironment(string prefix = DefaultEnvironmentVariablePrefix, IStaticRosterEnvironment? environment = null)` | Adds a user for every environment variable whose name starts with `prefix` (ordinal comparison) and is longer than it, using the rest of the name as the user id. Only variable names are read, never their values, and no display names or groups are inferred. `environment` supplies the names: `null` uses `ProcessStaticRosterEnvironment` (the current process environment), and a custom `IStaticRosterEnvironment` can supply them from elsewhere, for example in a test. `prefix` must not be `null` or empty. |
