- Machine roles: API keys and OAuth clients receive roles exactly like users; permission checks are identical (
{module}.{resource}.{action}). No unauthenticated endpoint except documented public write-key track ingestion (rate-limited, schema-validated, tenant-bound). - Member realm isolation: members live in a separate Better Auth realm; a member token can NEVER acquire console permissions; token exchange assertions are signed per-tenant, short-lived (≤5 min), single-use (jti replay check in Redis).
- national_id: masked by default everywhere; full read requires
core.contacts.read_national_id; every full read is audit-logged. Exports containing national_id require the same permission and are audit-logged as bulk access. - Webhooks out: existing HMAC signing + SSRF protections unchanged; PII inclusion in payloads is opt-in per endpoint, default OFF.
- IP allowlist: optional per-tenant hardening, default OFF (DEC-D6).
- Impersonation (Softcrum Ops): always time-boxed, reason-required, fully audit-logged, visible to the tenant in their audit trail.
Standard — Security (amendments v2)
- Machine roles: API keys and OAuth clients receive roles exactly like users; permission checks are identical (..).
⌘I