Skip to content

Auth and compliance end to end

Security in a Cratis application is not one feature in one package. A request crosses the edge, becomes an Arc command or query, writes events through Chronicle, builds read models, and comes back to a React screen. Authentication, authorization, tenant isolation, and compliance each belong to a different part of that journey, and the stack is designed so each concern has one clear owner. This page follows one request through those owners and points out where your own decisions still matter.

The short version: AuthProxy authenticates and resolves tenant context, Arc authorizes the operation, Chronicle stores events in the right namespace and encrypts PII by compliance subject, and Arc releases PII before query results reach the client.

Tenant-ID + identity

events + subject

Browser or API client

AuthProxy

authenticate + resolve tenant

Arc /.cratis/me

identity enrichment

Arc commands and queries

authorize operation

Chronicle

tenant namespace

Event log

PII encrypted by subject

Read models

encrypted at rest

Arc read-model release

decrypts for response

Components / React

typed result

Put AuthProxy in front of your frontend and backend services when you want one place to own the browser and API edge. It handles OpenID Connect, OAuth providers, JWT bearer authentication, provider selection, invite onboarding, tenant resolution, and routing.

AuthProxy then forwards requests with the resolved tenant and identity context. In an Arc application, the identity-enrichment endpoint is /.cratis/me: AuthProxy calls it, Arc composes the domain-specific identity payload, and the frontend can consume the resulting identity state instead of making every service rediscover the user.

Arc applies authorization where the behavior is declared: commands and queries. Use ASP.NET Core authorization attributes, Arc’s [Roles] convenience attribute, and policy-based authorization on the command record or read-model query method that represents the operation.

That matters because authorization happens before the behavior runs. If a command is not authorized, its Handle() method is not executed. If a query is not authorized, the read is not performed. The generated frontend proxy receives authorization state as part of the command or query result, so screens can react without hand-written protocol glue.

Use edge authentication for entry, then command/query authorization for business operations. Do not rely on the UI hiding a button as the only access-control layer.

Tenant context follows the request into Chronicle

Section titled “Tenant context follows the request into Chronicle”

In a multi-tenant Cratis application, the tenant resolved at the edge becomes application context in Arc. When Arc is integrated with Chronicle, that tenant context is used as the Chronicle namespace. Events, projections, reducers, and read models for one tenant go to that tenant’s namespace without every command manually choosing one.

This is the operational boundary:

ConcernOwnerResult
Resolve the tenantAuthProxy or Arc tenancy resolversOne tenant id for the request
Carry tenant through command/query handlingArcCommands, queries, filters, identity, and generated endpoints see the same tenant context
Isolate event-sourced stateArc + Chronicle integrationChronicle uses the tenant as the event-store namespace
Isolate MongoDB storageArc MongoDB integrationThe injected IMongoDatabase and IMongoCollection<T> resolve a tenant-specific database ({Database}+{TenantId} for non-default tenants)
Isolate EF Core storageYouArc does not append the tenant to the connection string; you choose and implement relational isolation
Check tenant membershipYouResolution selects a tenant; your services and policies verify that this caller may use it

Chronicle compliance uses a subject to identify whose protected data an event contains. That subject is the lookup key for PII encryption material. It is often a person or customer id; it is not always the authenticated user, and it is not always the aggregate id.

For example, an order event may be appended to an OrderId event source while the protected email address in the event belongs to a CustomerId. In that case the command should provide the customer as the Chronicle Subject. If no explicit subject is provided, Chronicle falls back to the event source id.

Arc’s Chronicle integration can resolve the subject from command return values, command properties, ICanProvideSubject, or a [Subject]-marked property. The rule of thumb is simple: set the subject to the identity that owns the PII, not merely the thing being changed.

PII is protected at write and released at read

Section titled “PII is protected at write and released at read”

Chronicle detects [PII] on event properties and on ConceptAs<T> value types. At append time, those values are encrypted under the subject’s key before they are stored in the event log.

Read models keep that protection:

Read-model styleHow PII is tracked
ProjectionChronicle can infer PII lineage from mapped event properties.
ReducerThe read model must mark PII properties explicitly, because reducer logic is arbitrary C#.
Arc query responseArc releases the read model before serving it, so clients receive decrypted values when the subject key exists.

Managed read-model documents also carry Chronicle’s reserved __subject field (and a __subjects map when properties belong to different subjects) so the correct key can be used during release. Do not declare your own properties named _subject, __subject, or __subjects; Chronicle reserves all three.

With Arc and Chronicle together, a command’s name and property values are written into the causation chain of the events it appends. That chain lives in the event log and is as permanent as the events, and it is not covered by event encryption. Mark top-level command properties [PII] or [NotAudited] to keep them out of it. The exclusion is not recursive: a marked member inside a nested object or collection is still written. Exclude the containing property, its type, or the whole command when nested data is sensitive. See causation.

For the concept and a comparison of erasure approaches, see Event sourcing and GDPR.

The event log can stay structurally immutable while protected values become unreadable. For GDPR-style erasure, Chronicle deletes the subject’s PII encryption key. After that, PII encrypted with that key cannot be decrypted by the running system.

Erasure also records a fence that prevents Chronicle from silently creating a replacement key for that subject in the affected namespace. It does not automatically remove stored ciphertext. Do not assume a replay or rebuild will clean it up: processing a protected value for an erased subject can fail with EncryptionKeyErased. Follow the subject-erasure procedure for the affected namespaces and read models. Authorizing a new key is a separate decision, not a step needed to finish erasure. If an entire event payload must be removed, review event redaction as a separate operation.

Key deletion only reaches what Chronicle’s key store protects. Plan for the rest:

  • Backups. A backup taken before the erasure still holds the key. Restoring it brings the key back, so a restore needs its own procedure to re-apply erasures made since the backup.
  • Copies outside Chronicle. Decrypted values in exports, warehouses, search indexes, logs, caches, and anything a reactor sent to another system are outside the erasure.
  • Unmarked data. Values that were never marked [PII], including command values recorded in causation, were never encrypted and are not affected.

Erasing a subject and key lifecycle cover the full procedure.

DecisionAsk thisStart here
Identity providerWhere do browser users and API clients authenticate?AuthProxy authentication
Tenant resolutionWhich host, claim, route, or configured value selects the tenant?AuthProxy tenancy
Operation accessWhich roles or policies can run each command or query?Arc authorization
Compliance subjectWhose personal data does this event contain?Arc Chronicle subject
PII modelingWhich event properties or concepts are personal data?Chronicle compliance
Command auditWhich command values must stay out of the permanent causation record?Arc causation
ErasureWhat must be key-deleted, re-projected, redacted, or handled outside Chronicle?Erasing a subject