FabricFabricPlatform
Composable application standard

Identity and tenancy

Turning a credential into actor context, and why proving who someone is says nothing about where they may act.

Every governed action, projection decision, grant and audit record derives from actor context. It is the first thing to get right, and the most expensive to retrofit: change it after your integrations are built and you rebuild the integrations.

The platform does not authenticate

PlatformHost accepts actorId and actorType and trusts them. That is deliberate — it has no opinion about your identity provider — but it means something upstream must establish identity before the platform is called, and that something is yours.

IdentityPort is the seam. It is OAuth2/OIDC-shaped, so a gateway that already validates JWTs implements it without a second identity model.

const claims = await identity.verify(credential);
if (!claims) throw new Error("unauthenticated");

verify returns null for anything it cannot positively verify. It never returns partially trusted claims, and it never echoes credential material back — identityPortChecks asserts both.

Verification is half the job

A credential proves who the caller is. It does not prove they may act in the tenant and space this particular request names. A valid credential for one tenant, replayed against another, is a valid credential.

// Refuses expired, not-yet-valid, cross-tenant and out-of-space claims.
const actor = actorContextFromClaims(claims, { tenantId, spaceId });

Derive the submission fields from claims that passed this check rather than from request input. That is what keeps the audit trail tied to something that was actually proven.

Three details that decide whether this fails open

Space coverage is spelled out. spaceIds is either an explicit array or the literal "tenant-wide". There is no absent-means-everything case, because claims that simply forgot to carry coverage would otherwise read as covering everything.

Timestamps carry an offset. issuedAt and expiresAt must be RFC 3339 with an explicit offset. Date.parse accepts timezone-less strings and reads them in the host's local zone, which would make the same credential expire at different instants on different machines.

The clock is checked before it is trusted. Every comparison against an invalid clock is false, so an unvalidated now would let an expired credential through rather than reject it.

Actor kinds

Six, not two: natural_person, agent, system, service_account, external_system, integration. Policy treats them by capability rather than by kind, but a gateway design has to handle the last three differently from a human session, and they are easy to discover late.

What is still yours

Session management, token refresh, the login surface, and mapping your provider's claims onto ActorClaims. Fabric defines what verified identity looks like once it reaches the platform.

On this page