feat: implement authentication and RBAC

- packages/auth: Argon2id password hashing, JWT access tokens (jose),
  opaque refresh tokens with rotation, generic error messages (no
  user-enumeration via timing or message differences)
- roles/permissions/role_permissions/user_roles/sessions/audit_logs schema
  (agente.md secoes 142-150); RBAC scope PLATFORM vs TENANT
- withUserContext(): narrow RLS exception so a user can discover their own
  tenant_memberships before a tenant is chosen (login flow)
- userHasPermission()/isPlatformUser(): explicit service-layer RBAC checks
  (roles/permissions tables are not RLS-protected — documented why in
  docs/AUTHENTICATION.md)
- seed: permission catalog, 4 system roles, initial Platform Super Admin
  (password written once to FIRST_LOGIN.txt, 600, outside Git)
- automated end-to-end test: login, RBAC check, refresh rotation, logout
This commit is contained in:
2026-08-28 05:58:49 -03:00
parent d66170c795
commit 70c5586595
16 changed files with 1172 additions and 10 deletions

165
pnpm-lock.yaml generated
View File

@@ -12,6 +12,25 @@ importers:
specifier: ^5.9.3
version: 5.9.3
packages/auth:
dependencies:
'@b2bcall/database':
specifier: workspace:*
version: link:../database
'@node-rs/argon2':
specifier: ^2.1.0
version: 2.1.0
jose:
specifier: ^6.2.10
version: 6.2.10
devDependencies:
tsx:
specifier: ^4.23.12
version: 4.23.12
typescript:
specifier: ^5.7.0
version: 5.9.3
packages/database:
dependencies:
'@prisma/adapter-pg':
@@ -239,6 +258,92 @@ packages:
cpu: [x64]
os: [win32]
'@node-rs/argon2-android-arm-eabi@2.1.0':
resolution: {integrity: sha512-hdWo5kb4eFRbHjdu4O6dVlRPI/CR1vbkJpe3Z9kF2s0Kp42428wg8AxI+8Cv4mygdW309BpUBf3sZaqXBNpdpw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [android]
'@node-rs/argon2-android-arm64@2.1.0':
resolution: {integrity: sha512-MHby1n9UzlVma3GiEYWNNqRhn2Z/90QwF2PFckGwucdz0HfdVX+lSKEcyfwcbvS5sJ9GAzhop3hXlUPxUYe72Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
'@node-rs/argon2-darwin-arm64@2.1.0':
resolution: {integrity: sha512-5nayvL9wepOvTO5JmdaiDZ6bgHEsI/vksnXphM3UTy/cflARr9MoD1pBrMPs921hx2otURJhG0avg9hN0Q0KPw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@node-rs/argon2-darwin-x64@2.1.0':
resolution: {integrity: sha512-7bFf3qH/PLQ5kU5GkxMF+dMz/tiT+0yFXILpOx4fgSFjw3wdXpGZt3wH4i6dHMURDcwYlNap0hJaX4h2E3JGng==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@node-rs/argon2-freebsd-x64@2.1.0':
resolution: {integrity: sha512-01mVdl+7bjSW0to5xcEzueq7BuYbz3476/dmLMXziJf8fhykzr723YRNcGjOcHSU5fxNrElY9uVeUoow16vBrQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
'@node-rs/argon2-linux-arm-gnueabihf@2.1.0':
resolution: {integrity: sha512-NxZILF+Hqav6yzJTUFuZXTUC1VagTO4Vfd2HSlzkwankUa1B7goo0NLY2tUPw6MdqtLojkqVG5MZ26AaF49tHw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@node-rs/argon2-linux-arm64-gnu@2.1.0':
resolution: {integrity: sha512-jpx2VwJLyAF/cM64HRigFBk67GwtQBcssYyVhvHqfmCEZz/CP//SV9bxE+uJOGIPKJo7wDg/5f2k3JY0PNMROg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@node-rs/argon2-linux-arm64-musl@2.1.0':
resolution: {integrity: sha512-xXAaPUlnPx/44qwaSekTG/g6/h5QCyrTayPLmvewJNyYz17vyBRmFKWLgv9Q3+NJwSvV88nVnCu/xkQbEPQaog==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@node-rs/argon2-linux-x64-gnu@2.1.0':
resolution: {integrity: sha512-ICnfyFaxZzr8OdAEwTPsAjx6gpNla1sI3miZJWAVCtZlw98Wo3Wd4H7tvW6S2NRJ1BIOf4l8Z7aX7h3fimXn5w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@node-rs/argon2-linux-x64-musl@2.1.0':
resolution: {integrity: sha512-f56jehb/IPTGBWWrvMjDGZWlQm/hKkH2VK/MxJ9u3kUR9PCacdtLFZmX4sL+qKeo4wsyhlD1EvlZF6nV1FSi3Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@node-rs/argon2-win32-arm64-msvc@2.1.0':
resolution: {integrity: sha512-KH8lBdjoZLUiVG1GjJQIQPKhmddJmEbJbL+e3S7BKVq1wKl1mx+ClmhGtMtYp8ZtEIw8/BYIFUIjL3sBuWGEuQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@node-rs/argon2-win32-ia32-msvc@2.1.0':
resolution: {integrity: sha512-zZ7NDHoKTgrjoUehNN7xvP+dA/M9krOp42l0MKns6TnMkwrp5nes9agEZsUy+0t0JoR8OQ8D7EUCNLh5BEn++w==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
'@node-rs/argon2-win32-x64-msvc@2.1.0':
resolution: {integrity: sha512-JN/yNiX7u8Cw9XXTbRrjnlgzFjCiEQe6x97wJnMIsJ3vty89q0SAg504Otd9qy2ofQS2F5CCWvrOXhm/oyHaAQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@node-rs/argon2@2.1.0':
resolution: {integrity: sha512-VBOWfM2u58/to3DFqTGJ2U5cJKQwmjN2zxzsQNZ5a2o8Z6aUrhvqQh8NdgotIF1Y0tMsBNtzOBDBdfvvkwJDSQ==}
engines: {node: '>= 10'}
'@prisma/adapter-pg@7.10.0':
resolution: {integrity: sha512-N7nwSor0HO1Kz6xBv0TPAjAPysKK0fac6p4fVN3ensLOuzc/83Fgmln5k92eK/cvzqdkSR/2kkAqlbcdwVrwpw==}
@@ -654,6 +759,9 @@ packages:
resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
hasBin: true
jose@6.2.10:
resolution: {integrity: sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==}
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
@@ -988,6 +1096,61 @@ snapshots:
'@esbuild/win32-x64@0.28.2':
optional: true
'@node-rs/argon2-android-arm-eabi@2.1.0':
optional: true
'@node-rs/argon2-android-arm64@2.1.0':
optional: true
'@node-rs/argon2-darwin-arm64@2.1.0':
optional: true
'@node-rs/argon2-darwin-x64@2.1.0':
optional: true
'@node-rs/argon2-freebsd-x64@2.1.0':
optional: true
'@node-rs/argon2-linux-arm-gnueabihf@2.1.0':
optional: true
'@node-rs/argon2-linux-arm64-gnu@2.1.0':
optional: true
'@node-rs/argon2-linux-arm64-musl@2.1.0':
optional: true
'@node-rs/argon2-linux-x64-gnu@2.1.0':
optional: true
'@node-rs/argon2-linux-x64-musl@2.1.0':
optional: true
'@node-rs/argon2-win32-arm64-msvc@2.1.0':
optional: true
'@node-rs/argon2-win32-ia32-msvc@2.1.0':
optional: true
'@node-rs/argon2-win32-x64-msvc@2.1.0':
optional: true
'@node-rs/argon2@2.1.0':
optionalDependencies:
'@node-rs/argon2-android-arm-eabi': 2.1.0
'@node-rs/argon2-android-arm64': 2.1.0
'@node-rs/argon2-darwin-arm64': 2.1.0
'@node-rs/argon2-darwin-x64': 2.1.0
'@node-rs/argon2-freebsd-x64': 2.1.0
'@node-rs/argon2-linux-arm-gnueabihf': 2.1.0
'@node-rs/argon2-linux-arm64-gnu': 2.1.0
'@node-rs/argon2-linux-arm64-musl': 2.1.0
'@node-rs/argon2-linux-x64-gnu': 2.1.0
'@node-rs/argon2-linux-x64-musl': 2.1.0
'@node-rs/argon2-win32-arm64-msvc': 2.1.0
'@node-rs/argon2-win32-ia32-msvc': 2.1.0
'@node-rs/argon2-win32-x64-msvc': 2.1.0
'@prisma/adapter-pg@7.10.0':
dependencies:
'@prisma/driver-adapter-utils': 7.10.0
@@ -1475,6 +1638,8 @@ snapshots:
jiti@2.7.0: {}
jose@6.2.10: {}
json-schema-traverse@1.0.0: {}
lodash@4.17.21: {}