Connect sync and domain services to app entitlements

Use this contract when a separately deployed sync or domain service must enforce the same app rights as Workspace. The service can introspect online, maintain a local projection, or validate a short-lived signed grant. Raw payment, identity, and provider evidence remains inside Workspace.

Choose an integration mode

ModeBest forContract
Native resolverCode in the same Workspace processDirect tenant-isolated domain call
IntrospectionOne online decisionCurrent state for one app actor
Snapshot and change feedA local service projectionFull initial state followed by ordered changes
Ed25519 grantShort offline decisionAudience-bound, short-lived signed evidence
WebhookLow-latency notificationAt-least-once delivery; the feed remains the reconciliation contract

For a standalone sync service, use snapshot and change feed as the default. Add webhooks for faster notification, not as a replacement for reconciliation.

Authenticate the service

An administrator creates a tenant- and app-bound service binding with an audience and the required capabilities, then rotates its credential. The secret is returned only when issued.

Send these headers with each authenticated request:

  • X-Workspace-Service-Credential
  • X-Workspace-Service-Timestamp
  • X-Workspace-Service-Nonce
  • X-Workspace-Service-Signature

The signature covers the HTTP method, full request URI including its query, timestamp, nonce, and SHA-256 body hash. Generate a fresh cryptographic nonce for every attempt. Stale timestamps, invalid signatures, and nonce reuse fail closed.

Use the endpoints

Method and pathPurpose
GET /api/v1/public/v1/app-entitlements/service/introspect/{actorId}Read one actor's current entitlement
GET /api/v1/public/v1/app-entitlements/service/snapshotLoad the paged initial state
GET /api/v1/public/v1/app-entitlements/service/changes?afterSequence=...Continue with ordered changes
POST /api/v1/public/v1/app-entitlements/service/grants/{actorId}Issue a short-lived grant
GET /api/v1/public/v1/app-entitlements/jwksLoad public Ed25519 verification keys

Persist asOfSequence from the first snapshot page. Send both cursor and the same asOfSequence on every following page, then consume changes after that sequence in ascending order. If the feed returns ERR_APP_ENTITLEMENT_CURSOR_EXPIRED, discard the local projection and start with a new snapshot.

Validate grants and webhooks

Cache the JWKS and validate signature, key ID, issuer, audience, and expiry. Never accept an expired grant or use it for another service binding.

Process webhooks durably before acknowledging them. Deduplicate by event ID and sequence. Delivery is at least once and may be delayed. Reconcile any gap through the change feed. Workspace permits only secured HTTPS targets and blocks private and loopback destinations; never place credentials in the target URL.

Verify the integration

Test valid introspection, snapshot/feed continuation, the wrong audience, an expired grant, stale timestamps, nonce replay, duplicate webhook delivery, and cursor expiry followed by a fresh snapshot. Do not derive rights directly from a provider notification or store payload. Workspace remains the entitlement authority.