Hexalith.Parties.Authentication 2.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Hexalith.Parties.Authentication --version 2.0.0
                    
NuGet\Install-Package Hexalith.Parties.Authentication -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hexalith.Parties.Authentication" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hexalith.Parties.Authentication" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Hexalith.Parties.Authentication" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hexalith.Parties.Authentication --version 2.0.0
                    
#r "nuget: Hexalith.Parties.Authentication, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hexalith.Parties.Authentication@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hexalith.Parties.Authentication&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Hexalith.Parties.Authentication&version=2.0.0
                    
Install as a Cake Tool

Hexalith.Parties

Hexalith.Parties is a ready-to-deploy party management domain service for people and organizations. Public command and query traffic goes through Hexalith.EventStore; the parties service runs an EventStore SDK domain-service host behind that gateway, and consumers normally use the typed .NET client package. The solution also includes parties-ui, a Blazor Server browser UI/BFF for the Admin and Consumer experiences.

GDPR Notice: Some GDPR infrastructure exists, and crypto-shredding is enabled by default, but the default key store is LocalDevKeyStorageBackend (in-memory, dev-only). Do not store regulated EU personal data until a production KMS or secret-store-backed key provider is provisioned. The MVP warning switch is separate from the crypto feature; see deployment-guide.md for the current runtime ownership boundary.

Consuming the Parties Aspire helper

Hexalith.Parties.Aspire adds the separately built Parties server to a consuming AppHost with AddHexalithPartiesServer(eventStore, daprConfigPath). It delegates state-store, pub/sub, health and sidecar wiring to Hexalith.EventStore.Aspire; the package does not depend on the Parties server. The consumer supplies Gateway routing, JWT validation and the app-channel token through platform helpers. Source is resolved only in the owning repository or its direct references/Hexalith.Parties checkout, and must be built before launch. The helper is included in the normal protected release; adding source does not mean a version is published or approved for downstream enrollment.

Key Features

  • EventStore gateway -- Public command/query ingress uses POST /api/v1/commands and POST /api/v1/queries with Domain="party".
  • Parties domain-service host -- The parties resource owns domain execution and SDK projection/query handlers behind EventStore.
  • Typed client package -- IPartiesCommandClient and IPartiesQueryClient hide EventStore envelope plumbing for .NET consumers.
  • Parties UI/BFF -- parties-ui is a Blazor Server host with FrontComposer, FluentUI, host-owned OIDC, role-gated Admin/Consumer areas, accessibility gates, and server-side token handling.
  • Admin portal RCL -- Hexalith.Parties.AdminPortal provides the protected /admin/parties* browse/detail/create/edit/GDPR surfaces embedded by parties-ui.
  • Consumer portal RCL -- Hexalith.Parties.ConsumerPortal provides the protected /me* Consumer profile, consent, data export, erasure, and processing-transparency surfaces embedded by parties-ui.
  • Embeddable party picker -- Hexalith.Parties.Picker provides a Blazor/custom-element selector that searches through IPartiesQueryClient and emits durable party-id selections.
  • Separate MCP host -- parties-mcp exposes create_party, get_party, find_parties, update_party, and delete_party through the typed client boundary.
  • DAPR event subscription -- Subscriber apps consume EventStore-published party events with their own idempotent handlers.
  • EventStore Admin UI -- Use eventstore-admin-ui for generic stream and event browsing.
  • .NET Aspire -- One-command local topology with EventStore, Parties, Parties UI, Tenants, DAPR sidecars, Redis, and optional Keycloak.

Quick Start

Set HEXALITH_DAPR_HOME to a prepared, absolute isolated Dapr home before starting. Follow the pinned Platform runtime prerequisites; the tool refuses an unset or unprepared home.

git clone https://github.com/Hexalith/Hexalith.Parties.git
cd Hexalith.Parties
git submodule update --init references/Hexalith.Platform references/Hexalith.Builds references/Hexalith.Commons references/Hexalith.EventStore references/Hexalith.FrontComposer references/Hexalith.PolymorphicSerializations references/Hexalith.Tenants references/Hexalith.Memories references/Hexalith.McpCli
dotnet tool restore
dotnet tool run hexalith-module -- debug --manifest module/hexalith.module-manifest.v2.json

The repository pins accepted module tool 4.34.0 alongside aspirate. From this independent checkout, debug resolves direct references once, builds the selected source projects in Debug, and waits for exactly parties, eventstore, tenants, tenants-api, memories, memories-access-telemetry-clock, and memories-access-telemetry. The tool reports its run ID and source mapping; attach the debugger to the Parties service child process. Stop that exact environment with dotnet tool run hexalith-module -- down --manifest module/hexalith.module-manifest.v2.json --run-id <run-id>. Initialize only this checkout's direct references; leave their nested references uninitialized. Ordinary package CI keeps package references and Release builds.

The owner ACL remains src/Hexalith.Parties.AppHost/DaprComponents/accesscontrol.parties.yaml. The renderer derives only callers and invocationRules from that ACL; its TEMPLATE in scripts/render-platform-declaration.py owns all other declaration fields. The strict parser accepts exactly thirteen unique POST routes from EventStore with the existing deny defaults, trust domain and namespace. After an owner-approved ACL change, run python3 scripts/render-platform-declaration.py; adding or removing routes also requires an approved update to the parser's thirteen-route invariant and its tests. Change TEMPLATE for non-ACL declaration updates, then regenerate. CI requires python3 scripts/render-platform-declaration.py --check and validates the generated declaration with its reference declarations using the pinned tool. Platform binds security storage through Parties:Security:StateStoreName and the existing projection/mapping component keys. The declarative tenant subscription uses system.tenants.events at /tenants/events; rich Memories search stays disabled.

Legacy hosting scope: Hexalith.Parties.AppHost, Aspire helpers, UI, proprietary MCP and sample hosts remain for existing owner tests and continuity. They are frozen and are outside this Platform qualification. The legacy local command is aspire run --apphost src/Hexalith.Parties.AppHost; its Keycloak, admin and UI topology is separate from the seven-server minimum above. Retirement requires owner-approved parity and consumer-removal gates.

Prerequisite - tenant access state. Provision or use an active Hexalith.Tenants tenant membership before the first Parties call. EventStore owns public authentication, tenant validation, RBAC, command/query routing, and generic response mapping. Parties consumes the authorized command/query behind the domain-service host and does not manage tenant lifecycle or roles itself.

The internal DAPR access-control policy is deny-by-default and permits only the eventstore app ID to invoke the SDK domain routes: /process, /query, /admin/operational-index-metadata, /project, /project/v2, /project/v2/reconcile, /replay-state, /project/rebuild/v1, /project/rebuild/shared/v1, /project/rebuild/stage/v1, /project/rebuild/commit/v1, /project/rebuild/abort/v1, and /project/rebuild/verify/v1. One documented exception: accesscontrol.eventstore-admin.yaml is defaultAction: allow at the top level, because local self-hosted DAPR does not reliably expose caller identity without mTLS (see docs/event-publishing.md for the full rationale). Runtime deployment orchestration is externally owned; the external orchestrator owns manifests, environment secrets, ingress, promotion, and rollback. This repository publishes immutable workload images and retains only local AppHost wiring.

See the Getting Started Guide for the full EventStore-fronted walkthrough.

Documentation

Project Structure

The repository contains exactly 14 projects under src plus one sample project, 16 runnable .NET test projects plus one support host (Hexalith.Parties.EventStoreGateway.TestHost), with Playwright e2e coverage alongside them. Adopter-facing packages (left column) are the only modules consumers normally reference directly. Modules under "Internal" are private to the domain-service host and not adopter-facing dependencies — do not reference them from consumer applications.

Hexalith.Parties/
  src/
    Hexalith.Parties.AppHost/        # Aspire orchestration (entry point, dev-only)
    Hexalith.Parties.Aspire/         # platform composition helper; no server package dependency
    # Adopter-facing
    Hexalith.Parties.Client/         # Typed EventStore gateway client (IPartiesCommandClient / IPartiesQueryClient)
    Hexalith.Parties.Contracts/      # Shared DTOs, commands, events, value objects
    Hexalith.Parties.AdminPortal/    # Protected Admin party records and GDPR RCL
    Hexalith.Parties.ConsumerPortal/ # Protected Consumer /me self-service RCL
    Hexalith.Parties.Picker/         # Embeddable Blazor/custom-element party picker
    Hexalith.Parties.UI/             # Blazor Server browser UI/BFF for Admin and Consumer experiences
    Hexalith.Parties.Mcp/            # Separate parties-mcp host over the typed client
    # Internal (domain-service-host private — not adopter-facing dependencies)
    Hexalith.Parties.Authentication/ # Internal claims-transformation library; packable but not adopter-facing. Retained as the rollback surface until 8.8 runtime-boundary cleanup proves G7/G9 parity
    Hexalith.Parties/                # SDK domain-service host and PartyAggregate behind EventStore
    Hexalith.Parties.Projections/    # SDK projection/query handlers and read models (internal)
    Hexalith.Parties.Security/       # GDPR payload protection and erasure infrastructure
    Hexalith.Parties.Testing/        # Test utilities
  tests/                             # Unit, integration, and architectural tests
  samples/
    Hexalith.Parties.Sample/         # Sample integration project
  docs/
    getting-started.md               # Step-by-step onboarding guide
  references/
    Hexalith.Builds/                 # Shared build configuration
    Hexalith.Commons/                # Shared platform helpers
    Hexalith.EventStore/             # Gateway/eventing submodule
    Hexalith.FrontComposer/          # UI shell submodule
    Hexalith.PolymorphicSerializations/ # Source generators / serialization helpers
    Hexalith.Tenants/                # Tenancy submodule
    Hexalith.Memories/               # Optional rich-search submodule

Positioning

Hexalith.Parties manages party records -- people and organizations with contact channels and identifiers. It is not an authentication provider, CRM, or identity server. Use it as the party/contact data backbone behind your own application logic.

Prerequisites

License

This project is licensed under the MIT License.

Generic McpCli command declarations (local migration increment)

The Contracts assembly declares exactly parties.create-party, parties.update-party, parties.reactivate-party and parties.deactivate-party. The module uses String identifiers, domain party, the existing full CLR command wire names, and root PartyId for aggregate routing. Tenant authority remains in the gateway envelope. Hexalith.McpCli.Abstractions 1.0.0 supplies declaration attributes only; the package/source pair follows UseHexalithProjectReferences. This increment does not enroll or publish a module or retire the legacy host.

McpCli payloads use exact CLR property casing and typed nested values. For example, parties.create-party accepts:

{"PartyId":"party-49","Type":"Person","PersonDetails":{"FirstName":"Ada","LastName":"Lovelace"},"ContactChannels":[{"PartyId":"party-49","ContactChannelId":"email-49","Type":"Email","Value":"ada@example.test","IsPreferred":true}]}

Supply IDs explicitly; every child PartyId must equal the root. No alias mapping, ID generation, person/organization inference or read/merge patch is performed. McpCli PartyId values use ASCII letters or digits plus ., _ or -, start and end with an ASCII letter or digit, and contain at most 128 characters. McpCli refuses legacy braced, parenthesized and X-format GUID PartyId values before Gateway submission, although Parties accepts them. Preserving those legacy IDs or approving a conversion remains a C07 retirement gate. An update supplies complete PersonDetails or OrganizationDetails replacements and/or typed add, update or removal lists. A PartyId-only update is rejected; every UpdateContactChannels item must supply at least one of Type, Value or IsPreferred (including false). Activation is a separate command. Repeated soft deactivation is a safe no-op after lifecycle guards and never performs GDPR erasure.

Both shared composite validators enforce a maximum raw UTF-16 length of 512 per string and 4096 combined, without trimming or rewriting values. Every root, nested, child and removal string occurrence counts, including whitespace and repeated IDs. The tighter support-safe 128-character rule applies to PartyId, ContactChannelId, IdentifierId and removal ID entries. Business identifier Value strings retain the 512 UTF-16-unit limit. This is stricter than legacy wrapper counting of trimmed fields; the total budget can bind before the configured composite sub-operation cap (default 100). Explicit null lists and null list items reject; omitted lists retain empty defaults. Create counts 1 plus every item in ContactChannels and Identifiers toward the operation cap. Update counts each non-null details object plus every item in its five operation lists. Removing a channel ID also listed for addition or update rejects the entire update; adding and removing the same identifier ID also rejects. An existing channel ID listed for both addition and update has its addition skipped and its update applied. All these checks run before protected aggregate state is accessed.

The four local vectors in tests/conformance-vectors/mcpcli-v1/ target only the unpublished scratch package Hexalith.Parties.Contracts 0.0.0-story49. They include prerequisite writes, repeat deactivation and semantic parties.get-party postconditions using the approved PartyDetail / party-detail / PartyDetailProjectionQueryActor route. Those Query contracts do not exist in this increment: postconditions remain unexecuted until Story 4.10, which must rebind vectors to the complete immutable artifact. Shared-validator format and artifact checks do not prove handler effects. Stories 4.11/4.13 own parity and persistent semantic proof. Maintainer approval must name the exact artifact hash and shared validator revision. C06 error privacy, C07 legacy-ID reachability and C08 credential and cross-tenant authorization evidence remain replacement/retirement gates.

The detail kind on update must match the existing party type; an update cannot change that type. Omitted/null details preserve the existing object, while a supplied object replaces it completely. Create requires the detail kind matching Type, but also accepts/stores an extra opposite-kind object without changing Type. Business identifiers are added or removed; there is no identifier-update list. Contact updates require at least one non-null mutable member: omitted/null preserves that member, IsPreferred: false clears that channel's preference, and Value: "" replaces the value with an empty string. All contact kinds, including PostalAddress/SocialMedia, store a raw string; no structured format is defined. Preference is scoped to channel type; supply IsPreferred: true with a type change to reconcile preferences in the target type.

OrganizationDetails.IsNaturalPerson defaults to false and initializes party classification on create. Existing detail replacement changes the nested flag without updating the established party classification; these four operations do not provide a classification-change command. Lifecycle operations require an existing unrestricted party with current erasure status Active, including when requesting an already-current active state.

Generic McpCli read declarations (local candidate)

The Contracts candidate declares exactly seven operations: parties.get-party, parties.list-parties, parties.search-parties, parties.create-party, parties.update-party, parties.reactivate-party and parties.deactivate-party. The complete candidate still requires fresh maintainer approval, exact-source CI, and the protected owning release workflow before its published version can be pinned in Builds and enrolled in McpCli. The existing five-tool MCP host remains available; this declaration work does not authorize retirement.

Queries use domain party and envelope tenant authority. Detail uses wire type PartyDetail, projection party-detail, historical compatibility name PartyDetailProjectionQueryActor, and root PartyId. List and search use wire PartyIndex / PartySearch, projection party-index, compatibility name PartyIndexProjectionQueryActor, and aggregate parties. The current SDK PartyDetailQueryHandler, PartyIndexQueryHandler and PartySearchQueryHandler dispatch directly to canonical read models; actor compatibility fields do not prove actor execution. Omitted EntityId falls back to AggregateId; supplied EntityId must match before any read. String IDs retain existing Parties syntax; McpCli still refuses legacy braced, parenthesized and X-format GUID IDs.

Erased detail has the same safe not-found outcome as missing detail. Inactive detail stays visible. List accepts optional Type (Person or Organization), Active, and inclusive CreatedAfter, CreatedBefore, ModifiedAfter and ModifiedBefore instants with explicit offsets. Invalid instants and inverted ranges reject. Search accepts Query, Type and Active; it trims the query and uses case-insensitive, diacritic-normalized display-name matching, including fuzzy matches. Empty/whitespace query returns no matches. Date filters, CaseId, unknown fields and unsupported search modes reject rather than being ignored; legacy Lexical/DisplayName mode names remain accepted. Duplicate case aliases such as Type plus type reject. Filters and erasure suppression apply before paging and totals exclude erased entries.

The new Query DTOs have no payload paging members. When envelope Paging is present, it alone governs: size defaults to 20, position to offset 0, maximum size 100, and offsets must align with the effective size. A nonblank cursor cannot combine with an offset. Cursors bind query type, tenant, user, filters and size; changed scope rejects before reading. Response paging reports effective size/offset, filtered total, hasMore and nextCursor. When envelope Paging is absent, the legacy payload Page/PageSize behavior remains (page defaults to 1, size to 20, maximum 100; nonpositive values reject).

tests/conformance-vectors/mcpcli-v1/ contains seven vectors bound to the local 0.0.0-story410 artifact, with prerequisite creates and original write-vector Query postconditions retained. Shared McpCli validation and both-head replay check wire envelopes, filtered totals, paging and result assertions. Scripted replay does not prove live authorization, persisted domain effects or C06–C08; Stories 4.11/4.13 remain required before replacement or retirement.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.0 105 11/1/2026
2.0.0 106 10/28/2026
1.6.0 94 10/23/2026
1.5.2 94 10/21/2026
1.5.1 94 10/21/2026
1.5.0 97 10/18/2026
1.4.0 92 10/16/2026
1.3.0 96 10/13/2026
1.2.1 96 10/7/2026
1.2.0 94 10/7/2026
1.1.1 119 9/5/2026
1.1.0 125 9/5/2026
1.0.0 138 7/16/2026