Security model
The browser may request an operation; it may not choose who it is. The framework adapter is the enforcement point between your product session and @incld.
Trust boundaries
| Surface | Trusted for | Never trusted for |
|---|---|---|
| Browser | Desired resource, action, filters, form values | User, organization, requester, reviewer, actor, viewer, bearer credentials |
| Framework adapter | Session resolution and application authorization | Business side effects without an application handler |
| @incld API | Project authentication, entitlements, lifecycle rules, durability | Your application-specific permission model |
| Signed webhook | Authenticity and event integrity after verification | Exactly-once delivery |
| React component | Presentation and interaction behavior | Server-side authorization |
Approvals are a server authorization input
const tenantIncld = new Incld({
apiKey: process.env.INCLD_SECRET_KEY!,
scope: {
organizationId: session.organization.id,
userId: session.user.id,
},
})
const check = await tenantIncld.approvals.check({
resourceType: "release",
resourceId: release.id,
action: "publish",
})
if (!check.approved) throw new ForbiddenError("Approval required")
await releases.publish(release.id)
ApprovalGate is not enforcement
The React gate may hide or reveal controls, but a user can still craft an HTTP request. Recheck approval state in the server mutation that performs the protected action.
Webhook verification and replay safety
The framework adapter validates the signed timestamp and HMAC before parsing or dispatching an event. Keep the webhook secret environment-specific, rotate it deliberately, and reject delivery outside the configured tolerance.
Valid signatures do not provide exactly-once execution
Network failures can cause the same event to arrive more than once. Store or pass
event.idempotencyKey
to every side-effecting system.