Trust corridor
Every product action should pass through identity, tenant, permission, audit, and secret boundaries in that order.
- @nebutra/authBetter Auth on Postgres, session-based
- @nebutra/tenanttenant context and organization scoping
- @nebutra/permissionsRBAC and resource-action scopes
- @nebutra/auditsensitive operation trail
- @nebutra/vaultlocal and KMS-backed secret storage
What it owns
- Better Auth session/identity surface, with device-flow login and organization membership
- Permission gates, tenant context, audit events, and vault storage
- OAuth server and captcha boundaries for external identity flows
Where it stops
- UI checks call IAM contracts; they do not reimplement authorization.
- Secrets and audit behavior do not leak into app-local helpers.
How we know it works
- auth provider abstraction tests and permission concept docs
- audit and tenant package boundaries in AGENTS.md contracts
In code
1import { getVault } from "@nebutra/vault";
2
3const vault = await getVault();
4
5// Envelope encryption — AWS KMS unwraps the DEK per-record.
6const encrypted = await vault.encrypt(secretKey, {
7 tenantId: org.id,
8 metadata: { name: "OpenAI API Key", type: "api_key" },
9});
10
11const plaintext = await vault.decrypt(encrypted);Packages
8 packages in packages/iam.
Hash-chained, SHA-256 append-only audit log for actor/tenant actions. SOC 2-grade tamper detection, streaming export, and replay-safe queries.
Better Auth on Postgres — organization membership, device-flow login, MFA-enforced, session HMAC-signed. One identity layer, no vendor in the loop.
Bot challenge with Cloudflare Turnstile / hCaptcha / reCAPTCHA behind one verify() call. Server-side scoring, per-route enable, no third-party tracker on the client.
Shared actor primitive — usr_/svc_/api_ ID space, role/membership lookup, tenant attachment. The single identity object every iam package reads.
Your own OIDC identity provider — "Sign in with Nebutra" for third-party apps. Authorization code + PKCE, refresh-token rotation, consent, clients stored in Postgres.
RBAC + ABAC engine — CASL for in-process checks. defineAbility() server, <Can /> in React.
Request-scoped tenant context via AsyncLocalStorage, with Prisma RLS bridge. One tenantId resolves through middleware and propagates the whole stack.
Application-layer envelope encryption for customer secrets — AES-256-GCM, per-tenant DEK, KMS-wrapped. Audit-logged read/decrypt, zero plaintext at rest.