@portaidentity/server 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/applications/cache.d.ts +64 -0
- package/dist/applications/cache.d.ts.map +1 -0
- package/dist/applications/cache.js +161 -0
- package/dist/applications/cache.js.map +1 -0
- package/dist/applications/errors.d.ts +25 -0
- package/dist/applications/errors.d.ts.map +1 -0
- package/dist/applications/errors.js +31 -0
- package/dist/applications/errors.js.map +1 -0
- package/dist/applications/index.d.ts +17 -0
- package/dist/applications/index.d.ts.map +1 -0
- package/dist/applications/index.js +19 -0
- package/dist/applications/index.js.map +1 -0
- package/dist/applications/repository.d.ts +184 -0
- package/dist/applications/repository.d.ts.map +1 -0
- package/dist/applications/repository.js +367 -0
- package/dist/applications/repository.js.map +1 -0
- package/dist/applications/service.d.ts +160 -0
- package/dist/applications/service.d.ts.map +1 -0
- package/dist/applications/service.js +388 -0
- package/dist/applications/service.js.map +1 -0
- package/dist/applications/slugs.d.ts +61 -0
- package/dist/applications/slugs.d.ts.map +1 -0
- package/dist/applications/slugs.js +115 -0
- package/dist/applications/slugs.js.map +1 -0
- package/dist/applications/types.d.ts +129 -0
- package/dist/applications/types.d.ts.map +1 -0
- package/dist/applications/types.js +62 -0
- package/dist/applications/types.js.map +1 -0
- package/dist/auth/csrf.d.ts +71 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +112 -0
- package/dist/auth/csrf.js.map +1 -0
- package/dist/auth/email-renderer.d.ts +37 -0
- package/dist/auth/email-renderer.d.ts.map +1 -0
- package/dist/auth/email-renderer.js +116 -0
- package/dist/auth/email-renderer.js.map +1 -0
- package/dist/auth/email-service.d.ts +154 -0
- package/dist/auth/email-service.d.ts.map +1 -0
- package/dist/auth/email-service.js +415 -0
- package/dist/auth/email-service.js.map +1 -0
- package/dist/auth/email-transport.d.ts +65 -0
- package/dist/auth/email-transport.d.ts.map +1 -0
- package/dist/auth/email-transport.js +82 -0
- package/dist/auth/email-transport.js.map +1 -0
- package/dist/auth/i18n.d.ts +81 -0
- package/dist/auth/i18n.d.ts.map +1 -0
- package/dist/auth/i18n.js +395 -0
- package/dist/auth/i18n.js.map +1 -0
- package/dist/auth/index.d.ts +28 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +31 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/interaction-authority.d.ts +39 -0
- package/dist/auth/interaction-authority.d.ts.map +1 -0
- package/dist/auth/interaction-authority.js +30 -0
- package/dist/auth/interaction-authority.js.map +1 -0
- package/dist/auth/magic-link-session.d.ts +81 -0
- package/dist/auth/magic-link-session.d.ts.map +1 -0
- package/dist/auth/magic-link-session.js +183 -0
- package/dist/auth/magic-link-session.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +143 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +220 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/auth/recovery-crypto.d.ts +34 -0
- package/dist/auth/recovery-crypto.d.ts.map +1 -0
- package/dist/auth/recovery-crypto.js +103 -0
- package/dist/auth/recovery-crypto.js.map +1 -0
- package/dist/auth/recovery-job-processor.d.ts +24 -0
- package/dist/auth/recovery-job-processor.d.ts.map +1 -0
- package/dist/auth/recovery-job-processor.js +123 -0
- package/dist/auth/recovery-job-processor.js.map +1 -0
- package/dist/auth/recovery-job-repository.d.ts +219 -0
- package/dist/auth/recovery-job-repository.d.ts.map +1 -0
- package/dist/auth/recovery-job-repository.js +340 -0
- package/dist/auth/recovery-job-repository.js.map +1 -0
- package/dist/auth/recovery-service.d.ts +27 -0
- package/dist/auth/recovery-service.d.ts.map +1 -0
- package/dist/auth/recovery-service.js +53 -0
- package/dist/auth/recovery-service.js.map +1 -0
- package/dist/auth/recovery-worker.d.ts +158 -0
- package/dist/auth/recovery-worker.d.ts.map +1 -0
- package/dist/auth/recovery-worker.js +306 -0
- package/dist/auth/recovery-worker.js.map +1 -0
- package/dist/auth/template-engine.d.ts +134 -0
- package/dist/auth/template-engine.d.ts.map +1 -0
- package/dist/auth/template-engine.js +225 -0
- package/dist/auth/template-engine.js.map +1 -0
- package/dist/auth/token-repository.d.ts +238 -0
- package/dist/auth/token-repository.d.ts.map +1 -0
- package/dist/auth/token-repository.js +475 -0
- package/dist/auth/token-repository.js.map +1 -0
- package/dist/auth/tokens.d.ts +45 -0
- package/dist/auth/tokens.d.ts.map +1 -0
- package/dist/auth/tokens.js +51 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +55 -0
- package/dist/cli/bootstrap.d.ts.map +1 -0
- package/dist/cli/bootstrap.js +90 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/commands/health.d.ts +20 -0
- package/dist/cli/commands/health.d.ts.map +1 -0
- package/dist/cli/commands/health.js +80 -0
- package/dist/cli/commands/health.js.map +1 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +349 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +19 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +88 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/seed.d.ts +19 -0
- package/dist/cli/commands/seed.d.ts.map +1 -0
- package/dist/cli/commands/seed.js +71 -0
- package/dist/cli/commands/seed.js.map +1 -0
- package/dist/cli/commands/user-2fa.d.ts +29 -0
- package/dist/cli/commands/user-2fa.d.ts.map +1 -0
- package/dist/cli/commands/user-2fa.js +113 -0
- package/dist/cli/commands/user-2fa.js.map +1 -0
- package/dist/cli/error-handler.d.ts +31 -0
- package/dist/cli/error-handler.d.ts.map +1 -0
- package/dist/cli/error-handler.js +65 -0
- package/dist/cli/error-handler.js.map +1 -0
- package/dist/cli/index.d.ts +48 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +94 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +124 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +48 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +96 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/clients/cache.d.ts +63 -0
- package/dist/clients/cache.d.ts.map +1 -0
- package/dist/clients/cache.js +160 -0
- package/dist/clients/cache.js.map +1 -0
- package/dist/clients/crypto.d.ts +69 -0
- package/dist/clients/crypto.d.ts.map +1 -0
- package/dist/clients/crypto.js +83 -0
- package/dist/clients/crypto.js.map +1 -0
- package/dist/clients/errors.d.ts +27 -0
- package/dist/clients/errors.d.ts.map +1 -0
- package/dist/clients/errors.js +33 -0
- package/dist/clients/errors.js.map +1 -0
- package/dist/clients/index.d.ts +19 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +23 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/clients/repository.d.ts +161 -0
- package/dist/clients/repository.d.ts.map +1 -0
- package/dist/clients/repository.js +318 -0
- package/dist/clients/repository.js.map +1 -0
- package/dist/clients/resolve-login-methods.d.ts +74 -0
- package/dist/clients/resolve-login-methods.d.ts.map +1 -0
- package/dist/clients/resolve-login-methods.js +68 -0
- package/dist/clients/resolve-login-methods.js.map +1 -0
- package/dist/clients/secret-repository.d.ts +109 -0
- package/dist/clients/secret-repository.d.ts.map +1 -0
- package/dist/clients/secret-repository.js +166 -0
- package/dist/clients/secret-repository.js.map +1 -0
- package/dist/clients/secret-service.d.ts +87 -0
- package/dist/clients/secret-service.d.ts.map +1 -0
- package/dist/clients/secret-service.js +204 -0
- package/dist/clients/secret-service.js.map +1 -0
- package/dist/clients/service.d.ts +158 -0
- package/dist/clients/service.d.ts.map +1 -0
- package/dist/clients/service.js +523 -0
- package/dist/clients/service.js.map +1 -0
- package/dist/clients/types.d.ts +214 -0
- package/dist/clients/types.d.ts.map +1 -0
- package/dist/clients/types.js +77 -0
- package/dist/clients/types.js.map +1 -0
- package/dist/clients/validators.d.ts +87 -0
- package/dist/clients/validators.d.ts.map +1 -0
- package/dist/clients/validators.js +164 -0
- package/dist/clients/validators.js.map +1 -0
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +52 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +35 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +167 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/custom-claims/cache.d.ts +48 -0
- package/dist/custom-claims/cache.d.ts.map +1 -0
- package/dist/custom-claims/cache.js +122 -0
- package/dist/custom-claims/cache.js.map +1 -0
- package/dist/custom-claims/errors.d.ts +25 -0
- package/dist/custom-claims/errors.d.ts.map +1 -0
- package/dist/custom-claims/errors.js +31 -0
- package/dist/custom-claims/errors.js.map +1 -0
- package/dist/custom-claims/index.d.ts +14 -0
- package/dist/custom-claims/index.d.ts.map +1 -0
- package/dist/custom-claims/index.js +17 -0
- package/dist/custom-claims/index.js.map +1 -0
- package/dist/custom-claims/repository.d.ts +147 -0
- package/dist/custom-claims/repository.d.ts.map +1 -0
- package/dist/custom-claims/repository.js +338 -0
- package/dist/custom-claims/repository.js.map +1 -0
- package/dist/custom-claims/service.d.ts +129 -0
- package/dist/custom-claims/service.d.ts.map +1 -0
- package/dist/custom-claims/service.js +296 -0
- package/dist/custom-claims/service.js.map +1 -0
- package/dist/custom-claims/types.d.ts +132 -0
- package/dist/custom-claims/types.d.ts.map +1 -0
- package/dist/custom-claims/types.js +61 -0
- package/dist/custom-claims/types.js.map +1 -0
- package/dist/custom-claims/validators.d.ts +61 -0
- package/dist/custom-claims/validators.d.ts.map +1 -0
- package/dist/custom-claims/validators.js +136 -0
- package/dist/custom-claims/validators.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/admin-permissions.d.ts +147 -0
- package/dist/lib/admin-permissions.d.ts.map +1 -0
- package/dist/lib/admin-permissions.js +261 -0
- package/dist/lib/admin-permissions.js.map +1 -0
- package/dist/lib/audit-log.d.ts +45 -0
- package/dist/lib/audit-log.d.ts.map +1 -0
- package/dist/lib/audit-log.js +79 -0
- package/dist/lib/audit-log.js.map +1 -0
- package/dist/lib/branding-assets.d.ts +47 -0
- package/dist/lib/branding-assets.d.ts.map +1 -0
- package/dist/lib/branding-assets.js +93 -0
- package/dist/lib/branding-assets.js.map +1 -0
- package/dist/lib/bulk-operations.d.ts +54 -0
- package/dist/lib/bulk-operations.d.ts.map +1 -0
- package/dist/lib/bulk-operations.js +201 -0
- package/dist/lib/bulk-operations.js.map +1 -0
- package/dist/lib/cursor.d.ts +110 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +115 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/data-export.d.ts +67 -0
- package/dist/lib/data-export.d.ts.map +1 -0
- package/dist/lib/data-export.js +272 -0
- package/dist/lib/data-export.js.map +1 -0
- package/dist/lib/data-import-plan.d.ts +50 -0
- package/dist/lib/data-import-plan.d.ts.map +1 -0
- package/dist/lib/data-import-plan.js +235 -0
- package/dist/lib/data-import-plan.js.map +1 -0
- package/dist/lib/data-import.d.ts +276 -0
- package/dist/lib/data-import.d.ts.map +1 -0
- package/dist/lib/data-import.js +1694 -0
- package/dist/lib/data-import.js.map +1 -0
- package/dist/lib/database.d.ts +22 -0
- package/dist/lib/database.d.ts.map +1 -0
- package/dist/lib/database.js +103 -0
- package/dist/lib/database.js.map +1 -0
- package/dist/lib/entity-history.d.ts +52 -0
- package/dist/lib/entity-history.d.ts.map +1 -0
- package/dist/lib/entity-history.js +121 -0
- package/dist/lib/entity-history.js.map +1 -0
- package/dist/lib/etag.d.ts +92 -0
- package/dist/lib/etag.d.ts.map +1 -0
- package/dist/lib/etag.js +155 -0
- package/dist/lib/etag.js.map +1 -0
- package/dist/lib/image-validator.d.ts +44 -0
- package/dist/lib/image-validator.d.ts.map +1 -0
- package/dist/lib/image-validator.js +204 -0
- package/dist/lib/image-validator.js.map +1 -0
- package/dist/lib/logger.d.ts +15 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +84 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/migrator.d.ts +14 -0
- package/dist/lib/migrator.d.ts.map +1 -0
- package/dist/lib/migrator.js +34 -0
- package/dist/lib/migrator.js.map +1 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.d.ts.map +1 -0
- package/dist/lib/redis.js +29 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/runtime-paths.d.ts +38 -0
- package/dist/lib/runtime-paths.d.ts.map +1 -0
- package/dist/lib/runtime-paths.js +50 -0
- package/dist/lib/runtime-paths.js.map +1 -0
- package/dist/lib/session-tracking.d.ts +81 -0
- package/dist/lib/session-tracking.d.ts.map +1 -0
- package/dist/lib/session-tracking.js +145 -0
- package/dist/lib/session-tracking.js.map +1 -0
- package/dist/lib/signing-key-crypto.d.ts +53 -0
- package/dist/lib/signing-key-crypto.d.ts.map +1 -0
- package/dist/lib/signing-key-crypto.js +108 -0
- package/dist/lib/signing-key-crypto.js.map +1 -0
- package/dist/lib/signing-keys.d.ts +141 -0
- package/dist/lib/signing-keys.d.ts.map +1 -0
- package/dist/lib/signing-keys.js +206 -0
- package/dist/lib/signing-keys.js.map +1 -0
- package/dist/lib/stats.d.ts +83 -0
- package/dist/lib/stats.d.ts.map +1 -0
- package/dist/lib/stats.js +187 -0
- package/dist/lib/stats.js.map +1 -0
- package/dist/lib/super-admin-protection.d.ts +69 -0
- package/dist/lib/super-admin-protection.d.ts.map +1 -0
- package/dist/lib/super-admin-protection.js +102 -0
- package/dist/lib/super-admin-protection.js.map +1 -0
- package/dist/lib/system-config.d.ts +79 -0
- package/dist/lib/system-config.d.ts.map +1 -0
- package/dist/lib/system-config.js +159 -0
- package/dist/lib/system-config.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +100 -0
- package/dist/middleware/admin-auth.d.ts.map +1 -0
- package/dist/middleware/admin-auth.js +241 -0
- package/dist/middleware/admin-auth.js.map +1 -0
- package/dist/middleware/admin-cors.d.ts +41 -0
- package/dist/middleware/admin-cors.d.ts.map +1 -0
- package/dist/middleware/admin-cors.js +83 -0
- package/dist/middleware/admin-cors.js.map +1 -0
- package/dist/middleware/admin-mutation-audit.d.ts +9 -0
- package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
- package/dist/middleware/admin-mutation-audit.js +76 -0
- package/dist/middleware/admin-mutation-audit.js.map +1 -0
- package/dist/middleware/admin-rate-limiter.d.ts +56 -0
- package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/admin-rate-limiter.js +97 -0
- package/dist/middleware/admin-rate-limiter.js.map +1 -0
- package/dist/middleware/client-secret-hash.d.ts +34 -0
- package/dist/middleware/client-secret-hash.d.ts.map +1 -0
- package/dist/middleware/client-secret-hash.js +74 -0
- package/dist/middleware/client-secret-hash.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +3 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +93 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/health.d.ts +3 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +35 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/metrics.d.ts +40 -0
- package/dist/middleware/metrics.d.ts.map +1 -0
- package/dist/middleware/metrics.js +75 -0
- package/dist/middleware/metrics.js.map +1 -0
- package/dist/middleware/oidc-client-tenant.d.ts +37 -0
- package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
- package/dist/middleware/oidc-client-tenant.js +156 -0
- package/dist/middleware/oidc-client-tenant.js.map +1 -0
- package/dist/middleware/oidc-cors.d.ts +33 -0
- package/dist/middleware/oidc-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-cors.js +68 -0
- package/dist/middleware/oidc-cors.js.map +1 -0
- package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
- package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-preflight-cors.js +267 -0
- package/dist/middleware/oidc-preflight-cors.js.map +1 -0
- package/dist/middleware/prompt-login-reset.d.ts +103 -0
- package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
- package/dist/middleware/prompt-login-reset.js +204 -0
- package/dist/middleware/prompt-login-reset.js.map +1 -0
- package/dist/middleware/ready.d.ts +23 -0
- package/dist/middleware/ready.d.ts.map +1 -0
- package/dist/middleware/ready.js +60 -0
- package/dist/middleware/ready.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +27 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +46 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/middleware/require-permission.d.ts +28 -0
- package/dist/middleware/require-permission.d.ts.map +1 -0
- package/dist/middleware/require-permission.js +63 -0
- package/dist/middleware/require-permission.js.map +1 -0
- package/dist/middleware/require-user-organization.d.ts +18 -0
- package/dist/middleware/require-user-organization.d.ts.map +1 -0
- package/dist/middleware/require-user-organization.js +53 -0
- package/dist/middleware/require-user-organization.js.map +1 -0
- package/dist/middleware/root-page.d.ts +62 -0
- package/dist/middleware/root-page.d.ts.map +1 -0
- package/dist/middleware/root-page.js +134 -0
- package/dist/middleware/root-page.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +98 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +159 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/middleware/tenant-resolver.d.ts +37 -0
- package/dist/middleware/tenant-resolver.d.ts.map +1 -0
- package/dist/middleware/tenant-resolver.js +71 -0
- package/dist/middleware/tenant-resolver.js.map +1 -0
- package/dist/middleware/token-rate-limiter.d.ts +89 -0
- package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/token-rate-limiter.js +189 -0
- package/dist/middleware/token-rate-limiter.js.map +1 -0
- package/dist/oidc/account-finder.d.ts +52 -0
- package/dist/oidc/account-finder.d.ts.map +1 -0
- package/dist/oidc/account-finder.js +134 -0
- package/dist/oidc/account-finder.js.map +1 -0
- package/dist/oidc/adapter-factory.d.ts +90 -0
- package/dist/oidc/adapter-factory.d.ts.map +1 -0
- package/dist/oidc/adapter-factory.js +165 -0
- package/dist/oidc/adapter-factory.js.map +1 -0
- package/dist/oidc/configuration.d.ts +155 -0
- package/dist/oidc/configuration.d.ts.map +1 -0
- package/dist/oidc/configuration.js +531 -0
- package/dist/oidc/configuration.js.map +1 -0
- package/dist/oidc/postgres-adapter.d.ts +159 -0
- package/dist/oidc/postgres-adapter.d.ts.map +1 -0
- package/dist/oidc/postgres-adapter.js +222 -0
- package/dist/oidc/postgres-adapter.js.map +1 -0
- package/dist/oidc/protocol-security-observer.d.ts +38 -0
- package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
- package/dist/oidc/protocol-security-observer.js +93 -0
- package/dist/oidc/protocol-security-observer.js.map +1 -0
- package/dist/oidc/provider.d.ts +37 -0
- package/dist/oidc/provider.d.ts.map +1 -0
- package/dist/oidc/provider.js +71 -0
- package/dist/oidc/provider.js.map +1 -0
- package/dist/oidc/redis-adapter.d.ts +140 -0
- package/dist/oidc/redis-adapter.d.ts.map +1 -0
- package/dist/oidc/redis-adapter.js +344 -0
- package/dist/oidc/redis-adapter.js.map +1 -0
- package/dist/organizations/cache.d.ts +60 -0
- package/dist/organizations/cache.d.ts.map +1 -0
- package/dist/organizations/cache.js +157 -0
- package/dist/organizations/cache.js.map +1 -0
- package/dist/organizations/errors.d.ts +25 -0
- package/dist/organizations/errors.d.ts.map +1 -0
- package/dist/organizations/errors.js +31 -0
- package/dist/organizations/errors.js.map +1 -0
- package/dist/organizations/index.d.ts +15 -0
- package/dist/organizations/index.d.ts.map +1 -0
- package/dist/organizations/index.js +15 -0
- package/dist/organizations/index.js.map +1 -0
- package/dist/organizations/repository.d.ts +183 -0
- package/dist/organizations/repository.d.ts.map +1 -0
- package/dist/organizations/repository.js +354 -0
- package/dist/organizations/repository.js.map +1 -0
- package/dist/organizations/service.d.ts +168 -0
- package/dist/organizations/service.d.ts.map +1 -0
- package/dist/organizations/service.js +511 -0
- package/dist/organizations/service.js.map +1 -0
- package/dist/organizations/slugs.d.ts +57 -0
- package/dist/organizations/slugs.d.ts.map +1 -0
- package/dist/organizations/slugs.js +130 -0
- package/dist/organizations/slugs.js.map +1 -0
- package/dist/organizations/types.d.ts +146 -0
- package/dist/organizations/types.d.ts.map +1 -0
- package/dist/organizations/types.js +49 -0
- package/dist/organizations/types.js.map +1 -0
- package/dist/rbac/cache.d.ts +110 -0
- package/dist/rbac/cache.d.ts.map +1 -0
- package/dist/rbac/cache.js +271 -0
- package/dist/rbac/cache.js.map +1 -0
- package/dist/rbac/errors.d.ts +34 -0
- package/dist/rbac/errors.d.ts.map +1 -0
- package/dist/rbac/errors.js +43 -0
- package/dist/rbac/errors.js.map +1 -0
- package/dist/rbac/index.d.ts +17 -0
- package/dist/rbac/index.d.ts.map +1 -0
- package/dist/rbac/index.js +21 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/rbac/mapping-repository.d.ts +121 -0
- package/dist/rbac/mapping-repository.d.ts.map +1 -0
- package/dist/rbac/mapping-repository.js +224 -0
- package/dist/rbac/mapping-repository.js.map +1 -0
- package/dist/rbac/permission-repository.d.ts +100 -0
- package/dist/rbac/permission-repository.d.ts.map +1 -0
- package/dist/rbac/permission-repository.js +190 -0
- package/dist/rbac/permission-repository.js.map +1 -0
- package/dist/rbac/permission-service.d.ts +85 -0
- package/dist/rbac/permission-service.d.ts.map +1 -0
- package/dist/rbac/permission-service.js +179 -0
- package/dist/rbac/permission-service.js.map +1 -0
- package/dist/rbac/role-repository.d.ts +104 -0
- package/dist/rbac/role-repository.d.ts.map +1 -0
- package/dist/rbac/role-repository.js +202 -0
- package/dist/rbac/role-repository.js.map +1 -0
- package/dist/rbac/role-service.d.ts +111 -0
- package/dist/rbac/role-service.d.ts.map +1 -0
- package/dist/rbac/role-service.js +256 -0
- package/dist/rbac/role-service.js.map +1 -0
- package/dist/rbac/slugs.d.ts +116 -0
- package/dist/rbac/slugs.d.ts.map +1 -0
- package/dist/rbac/slugs.js +178 -0
- package/dist/rbac/slugs.js.map +1 -0
- package/dist/rbac/types.d.ts +187 -0
- package/dist/rbac/types.d.ts.map +1 -0
- package/dist/rbac/types.js +75 -0
- package/dist/rbac/types.js.map +1 -0
- package/dist/rbac/user-role-service.d.ts +101 -0
- package/dist/rbac/user-role-service.d.ts.map +1 -0
- package/dist/rbac/user-role-service.js +166 -0
- package/dist/rbac/user-role-service.js.map +1 -0
- package/dist/routes/applications.d.ts +40 -0
- package/dist/routes/applications.d.ts.map +1 -0
- package/dist/routes/applications.js +284 -0
- package/dist/routes/applications.js.map +1 -0
- package/dist/routes/audit.d.ts +31 -0
- package/dist/routes/audit.d.ts.map +1 -0
- package/dist/routes/audit.js +140 -0
- package/dist/routes/audit.js.map +1 -0
- package/dist/routes/branding.d.ts +17 -0
- package/dist/routes/branding.d.ts.map +1 -0
- package/dist/routes/branding.js +104 -0
- package/dist/routes/branding.js.map +1 -0
- package/dist/routes/bulk.d.ts +37 -0
- package/dist/routes/bulk.d.ts.map +1 -0
- package/dist/routes/bulk.js +94 -0
- package/dist/routes/bulk.js.map +1 -0
- package/dist/routes/clients.d.ts +44 -0
- package/dist/routes/clients.d.ts.map +1 -0
- package/dist/routes/clients.js +353 -0
- package/dist/routes/clients.js.map +1 -0
- package/dist/routes/config.d.ts +35 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +115 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/custom-claims.d.ts +38 -0
- package/dist/routes/custom-claims.d.ts.map +1 -0
- package/dist/routes/custom-claims.js +208 -0
- package/dist/routes/custom-claims.js.map +1 -0
- package/dist/routes/exports.d.ts +21 -0
- package/dist/routes/exports.d.ts.map +1 -0
- package/dist/routes/exports.js +98 -0
- package/dist/routes/exports.js.map +1 -0
- package/dist/routes/imports.d.ts +18 -0
- package/dist/routes/imports.d.ts.map +1 -0
- package/dist/routes/imports.js +72 -0
- package/dist/routes/imports.js.map +1 -0
- package/dist/routes/interactions.d.ts +111 -0
- package/dist/routes/interactions.d.ts.map +1 -0
- package/dist/routes/interactions.js +1074 -0
- package/dist/routes/interactions.js.map +1 -0
- package/dist/routes/invitation.d.ts +31 -0
- package/dist/routes/invitation.d.ts.map +1 -0
- package/dist/routes/invitation.js +342 -0
- package/dist/routes/invitation.js.map +1 -0
- package/dist/routes/keys.d.ts +28 -0
- package/dist/routes/keys.d.ts.map +1 -0
- package/dist/routes/keys.js +91 -0
- package/dist/routes/keys.js.map +1 -0
- package/dist/routes/magic-link.d.ts +43 -0
- package/dist/routes/magic-link.d.ts.map +1 -0
- package/dist/routes/magic-link.js +264 -0
- package/dist/routes/magic-link.js.map +1 -0
- package/dist/routes/organizations.d.ts +38 -0
- package/dist/routes/organizations.d.ts.map +1 -0
- package/dist/routes/organizations.js +347 -0
- package/dist/routes/organizations.js.map +1 -0
- package/dist/routes/password-reset.d.ts +65 -0
- package/dist/routes/password-reset.d.ts.map +1 -0
- package/dist/routes/password-reset.js +493 -0
- package/dist/routes/password-reset.js.map +1 -0
- package/dist/routes/permissions.d.ts +33 -0
- package/dist/routes/permissions.d.ts.map +1 -0
- package/dist/routes/permissions.js +166 -0
- package/dist/routes/permissions.js.map +1 -0
- package/dist/routes/roles.d.ts +37 -0
- package/dist/routes/roles.d.ts.map +1 -0
- package/dist/routes/roles.js +222 -0
- package/dist/routes/roles.js.map +1 -0
- package/dist/routes/sessions.d.ts +37 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +121 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stats.d.ts +28 -0
- package/dist/routes/stats.d.ts.map +1 -0
- package/dist/routes/stats.js +65 -0
- package/dist/routes/stats.js.map +1 -0
- package/dist/routes/two-factor-admin.d.ts +54 -0
- package/dist/routes/two-factor-admin.d.ts.map +1 -0
- package/dist/routes/two-factor-admin.js +344 -0
- package/dist/routes/two-factor-admin.js.map +1 -0
- package/dist/routes/two-factor.d.ts +31 -0
- package/dist/routes/two-factor.d.ts.map +1 -0
- package/dist/routes/two-factor.js +595 -0
- package/dist/routes/two-factor.js.map +1 -0
- package/dist/routes/user-roles.d.ts +33 -0
- package/dist/routes/user-roles.d.ts.map +1 -0
- package/dist/routes/user-roles.js +129 -0
- package/dist/routes/user-roles.js.map +1 -0
- package/dist/routes/users.d.ts +61 -0
- package/dist/routes/users.d.ts.map +1 -0
- package/dist/routes/users.js +868 -0
- package/dist/routes/users.js.map +1 -0
- package/dist/security/decision-context.d.ts +52 -0
- package/dist/security/decision-context.d.ts.map +1 -0
- package/dist/security/decision-context.js +150 -0
- package/dist/security/decision-context.js.map +1 -0
- package/dist/security/decision-event.d.ts +128 -0
- package/dist/security/decision-event.d.ts.map +1 -0
- package/dist/security/decision-event.js +225 -0
- package/dist/security/decision-event.js.map +1 -0
- package/dist/security/transport-decision.d.ts +6 -0
- package/dist/security/transport-decision.d.ts.map +1 -0
- package/dist/security/transport-decision.js +37 -0
- package/dist/security/transport-decision.js.map +1 -0
- package/dist/server.d.ts +50 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +491 -0
- package/dist/server.js.map +1 -0
- package/dist/two-factor/cache.d.ts +47 -0
- package/dist/two-factor/cache.d.ts.map +1 -0
- package/dist/two-factor/cache.js +122 -0
- package/dist/two-factor/cache.js.map +1 -0
- package/dist/two-factor/crypto.d.ts +41 -0
- package/dist/two-factor/crypto.d.ts.map +1 -0
- package/dist/two-factor/crypto.js +94 -0
- package/dist/two-factor/crypto.js.map +1 -0
- package/dist/two-factor/errors.d.ts +82 -0
- package/dist/two-factor/errors.d.ts.map +1 -0
- package/dist/two-factor/errors.js +112 -0
- package/dist/two-factor/errors.js.map +1 -0
- package/dist/two-factor/index.d.ts +18 -0
- package/dist/two-factor/index.d.ts.map +1 -0
- package/dist/two-factor/index.js +25 -0
- package/dist/two-factor/index.js.map +1 -0
- package/dist/two-factor/otp.d.ts +43 -0
- package/dist/two-factor/otp.d.ts.map +1 -0
- package/dist/two-factor/otp.js +57 -0
- package/dist/two-factor/otp.js.map +1 -0
- package/dist/two-factor/recovery.d.ts +45 -0
- package/dist/two-factor/recovery.d.ts.map +1 -0
- package/dist/two-factor/recovery.js +104 -0
- package/dist/two-factor/recovery.js.map +1 -0
- package/dist/two-factor/repository.d.ts +156 -0
- package/dist/two-factor/repository.d.ts.map +1 -0
- package/dist/two-factor/repository.js +251 -0
- package/dist/two-factor/repository.js.map +1 -0
- package/dist/two-factor/service.d.ts +232 -0
- package/dist/two-factor/service.d.ts.map +1 -0
- package/dist/two-factor/service.js +599 -0
- package/dist/two-factor/service.js.map +1 -0
- package/dist/two-factor/totp.d.ts +57 -0
- package/dist/two-factor/totp.d.ts.map +1 -0
- package/dist/two-factor/totp.js +96 -0
- package/dist/two-factor/totp.js.map +1 -0
- package/dist/two-factor/types.d.ts +152 -0
- package/dist/two-factor/types.d.ts.map +1 -0
- package/dist/two-factor/types.js +64 -0
- package/dist/two-factor/types.js.map +1 -0
- package/dist/users/cache.d.ts +49 -0
- package/dist/users/cache.d.ts.map +1 -0
- package/dist/users/cache.js +140 -0
- package/dist/users/cache.js.map +1 -0
- package/dist/users/claims.d.ts +67 -0
- package/dist/users/claims.d.ts.map +1 -0
- package/dist/users/claims.js +104 -0
- package/dist/users/claims.js.map +1 -0
- package/dist/users/errors.d.ts +25 -0
- package/dist/users/errors.d.ts.map +1 -0
- package/dist/users/errors.js +31 -0
- package/dist/users/errors.js.map +1 -0
- package/dist/users/gdpr.d.ts +110 -0
- package/dist/users/gdpr.d.ts.map +1 -0
- package/dist/users/gdpr.js +211 -0
- package/dist/users/gdpr.js.map +1 -0
- package/dist/users/index.d.ts +20 -0
- package/dist/users/index.d.ts.map +1 -0
- package/dist/users/index.js +19 -0
- package/dist/users/index.js.map +1 -0
- package/dist/users/password.d.ts +85 -0
- package/dist/users/password.d.ts.map +1 -0
- package/dist/users/password.js +138 -0
- package/dist/users/password.js.map +1 -0
- package/dist/users/repository.d.ts +263 -0
- package/dist/users/repository.d.ts.map +1 -0
- package/dist/users/repository.js +499 -0
- package/dist/users/repository.js.map +1 -0
- package/dist/users/service.d.ts +299 -0
- package/dist/users/service.d.ts.map +1 -0
- package/dist/users/service.js +698 -0
- package/dist/users/service.js.map +1 -0
- package/dist/users/types.d.ts +220 -0
- package/dist/users/types.d.ts.map +1 -0
- package/dist/users/types.js +77 -0
- package/dist/users/types.js.map +1 -0
- package/locales/default/en/common.json +10 -0
- package/locales/default/en/consent.json +13 -0
- package/locales/default/en/emails.json +17 -0
- package/locales/default/en/errors.json +21 -0
- package/locales/default/en/forgot-password.json +11 -0
- package/locales/default/en/invitation.json +18 -0
- package/locales/default/en/login.json +17 -0
- package/locales/default/en/logout.json +9 -0
- package/locales/default/en/magic-link.json +12 -0
- package/locales/default/en/reset-password.json +16 -0
- package/locales/default/en/two-factor.json +29 -0
- package/migrations/.gitkeep +0 -0
- package/migrations/001_extensions.sql +22 -0
- package/migrations/002_organizations.sql +43 -0
- package/migrations/003_applications.sql +50 -0
- package/migrations/004_clients.sql +74 -0
- package/migrations/005_users.sql +119 -0
- package/migrations/006_roles_permissions.sql +80 -0
- package/migrations/007_custom_claims.sql +55 -0
- package/migrations/008_config.sql +51 -0
- package/migrations/009_audit_log.sql +31 -0
- package/migrations/010_oidc_adapter.sql +34 -0
- package/migrations/011_seed.sql +53 -0
- package/migrations/012_two_factor.sql +88 -0
- package/migrations/013_client_secret_sha256.sql +22 -0
- package/migrations/014_login_methods.sql +34 -0
- package/migrations/015_signing_key_encryption.sql +20 -0
- package/migrations/016_failed_login_count.sql +27 -0
- package/migrations/017_audit_retention.sql +11 -0
- package/migrations/018_admin_api_enhancements.sql +78 -0
- package/migrations/019_invitation_details.sql +27 -0
- package/migrations/020_two_factor_admin_permission.sql +108 -0
- package/migrations/021_auth_recovery_jobs.sql +74 -0
- package/migrations/022_recovery_artifact_ownership.sql +25 -0
- package/migrations/023_magic_link_authority.sql +39 -0
- package/package.json +106 -0
- package/templates/default/emails/invitation.hbs +39 -0
- package/templates/default/emails/invitation.txt.hbs +18 -0
- package/templates/default/emails/magic-link.hbs +30 -0
- package/templates/default/emails/magic-link.txt.hbs +11 -0
- package/templates/default/emails/otp-code.hbs +31 -0
- package/templates/default/emails/otp-code.txt.hbs +15 -0
- package/templates/default/emails/password-changed.hbs +24 -0
- package/templates/default/emails/password-changed.txt.hbs +7 -0
- package/templates/default/emails/password-reset.hbs +30 -0
- package/templates/default/emails/password-reset.txt.hbs +11 -0
- package/templates/default/emails/welcome.hbs +25 -0
- package/templates/default/emails/welcome.txt.hbs +9 -0
- package/templates/default/layouts/main.hbs +49 -0
- package/templates/default/pages/accept-invite.hbs +25 -0
- package/templates/default/pages/consent.hbs +27 -0
- package/templates/default/pages/error.hbs +15 -0
- package/templates/default/pages/forgot-password.hbs +21 -0
- package/templates/default/pages/invite-expired.hbs +6 -0
- package/templates/default/pages/invite-success.hbs +9 -0
- package/templates/default/pages/login.hbs +108 -0
- package/templates/default/pages/logout-success.hbs +5 -0
- package/templates/default/pages/logout.hbs +24 -0
- package/templates/default/pages/magic-link-sent.hbs +10 -0
- package/templates/default/pages/magic-link-success.hbs +17 -0
- package/templates/default/pages/reset-password.hbs +20 -0
- package/templates/default/pages/reset-success.hbs +9 -0
- package/templates/default/pages/two-factor-setup.hbs +65 -0
- package/templates/default/pages/two-factor-verify.hbs +77 -0
- package/templates/default/partials/flash-messages.hbs +10 -0
- package/templates/default/partials/footer.hbs +4 -0
- package/templates/default/partials/header.hbs +8 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Applications represent SaaS products managed by Porta
|
|
4
|
+
CREATE TABLE applications (
|
|
5
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
6
|
+
name VARCHAR(255) NOT NULL, -- e.g., "BusinessSuite"
|
|
7
|
+
slug VARCHAR(100) NOT NULL UNIQUE, -- e.g., "business-suite"
|
|
8
|
+
description TEXT,
|
|
9
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
10
|
+
CHECK (status IN ('active', 'inactive', 'archived')),
|
|
11
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
12
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE TRIGGER set_updated_at
|
|
16
|
+
BEFORE UPDATE ON applications
|
|
17
|
+
FOR EACH ROW
|
|
18
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
19
|
+
|
|
20
|
+
COMMENT ON TABLE applications IS 'SaaS application definitions — each org uses the same app but with their own users/roles';
|
|
21
|
+
|
|
22
|
+
-- Application modules are logical groupings (e.g., CRM, Invoicing, HR)
|
|
23
|
+
-- Permissions are namespaced by module
|
|
24
|
+
CREATE TABLE application_modules (
|
|
25
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
26
|
+
application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
|
|
27
|
+
name VARCHAR(255) NOT NULL, -- e.g., "CRM"
|
|
28
|
+
slug VARCHAR(100) NOT NULL, -- e.g., "crm"
|
|
29
|
+
description TEXT,
|
|
30
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
31
|
+
CHECK (status IN ('active', 'inactive')),
|
|
32
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
33
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
34
|
+
|
|
35
|
+
UNIQUE (application_id, slug)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE INDEX idx_app_modules_application ON application_modules(application_id);
|
|
39
|
+
|
|
40
|
+
CREATE TRIGGER set_updated_at
|
|
41
|
+
BEFORE UPDATE ON application_modules
|
|
42
|
+
FOR EACH ROW
|
|
43
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
44
|
+
|
|
45
|
+
COMMENT ON TABLE application_modules IS 'Logical groupings within an application (e.g., CRM, Invoicing) — permissions are namespaced by module';
|
|
46
|
+
|
|
47
|
+
-- Down Migration
|
|
48
|
+
|
|
49
|
+
DROP TABLE IF EXISTS application_modules CASCADE;
|
|
50
|
+
DROP TABLE IF EXISTS applications CASCADE;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- OIDC clients — each represents a deployment type (web, mobile, SPA) of an app for an org
|
|
4
|
+
CREATE TABLE clients (
|
|
5
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
6
|
+
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
|
7
|
+
application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
|
|
8
|
+
client_id VARCHAR(255) NOT NULL UNIQUE, -- OIDC client_id (public identifier)
|
|
9
|
+
client_name VARCHAR(255) NOT NULL,
|
|
10
|
+
client_type VARCHAR(20) NOT NULL
|
|
11
|
+
CHECK (client_type IN ('confidential', 'public')),
|
|
12
|
+
application_type VARCHAR(20) NOT NULL DEFAULT 'web'
|
|
13
|
+
CHECK (application_type IN ('web', 'native', 'spa')),
|
|
14
|
+
|
|
15
|
+
-- OIDC Configuration
|
|
16
|
+
redirect_uris TEXT[] NOT NULL DEFAULT '{}', -- Array of allowed redirect URIs
|
|
17
|
+
post_logout_redirect_uris TEXT[] DEFAULT '{}',
|
|
18
|
+
grant_types TEXT[] NOT NULL DEFAULT '{authorization_code}',
|
|
19
|
+
response_types TEXT[] NOT NULL DEFAULT '{code}',
|
|
20
|
+
scope TEXT NOT NULL DEFAULT 'openid profile email',
|
|
21
|
+
token_endpoint_auth_method VARCHAR(50) NOT NULL DEFAULT 'client_secret_basic',
|
|
22
|
+
|
|
23
|
+
-- CORS
|
|
24
|
+
allowed_origins TEXT[] DEFAULT '{}', -- Allowed CORS origins
|
|
25
|
+
|
|
26
|
+
-- PKCE
|
|
27
|
+
require_pkce BOOLEAN NOT NULL DEFAULT TRUE,
|
|
28
|
+
|
|
29
|
+
-- Status
|
|
30
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
31
|
+
CHECK (status IN ('active', 'inactive', 'revoked')),
|
|
32
|
+
|
|
33
|
+
-- Metadata
|
|
34
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
35
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE INDEX idx_clients_org ON clients(organization_id);
|
|
39
|
+
CREATE INDEX idx_clients_app ON clients(application_id);
|
|
40
|
+
CREATE INDEX idx_clients_client_id ON clients(client_id);
|
|
41
|
+
|
|
42
|
+
CREATE TRIGGER set_updated_at
|
|
43
|
+
BEFORE UPDATE ON clients
|
|
44
|
+
FOR EACH ROW
|
|
45
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
46
|
+
|
|
47
|
+
COMMENT ON TABLE clients IS 'OIDC clients — each represents a deployment (web/mobile/SPA) of an application for an organization';
|
|
48
|
+
COMMENT ON COLUMN clients.client_id IS 'Public OIDC client_id — used in authorization requests';
|
|
49
|
+
COMMENT ON COLUMN clients.require_pkce IS 'Whether PKCE is required for this client (recommended: always true)';
|
|
50
|
+
|
|
51
|
+
-- Client secrets — stored as Argon2id hashes
|
|
52
|
+
-- Multiple active secrets support zero-downtime rotation
|
|
53
|
+
CREATE TABLE client_secrets (
|
|
54
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
55
|
+
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
|
56
|
+
secret_hash TEXT NOT NULL, -- Argon2id hash of the secret
|
|
57
|
+
label VARCHAR(255), -- Human-readable label
|
|
58
|
+
expires_at TIMESTAMPTZ, -- NULL = never expires
|
|
59
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
60
|
+
CHECK (status IN ('active', 'revoked')),
|
|
61
|
+
last_used_at TIMESTAMPTZ,
|
|
62
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE INDEX idx_client_secrets_client ON client_secrets(client_id);
|
|
66
|
+
CREATE INDEX idx_client_secrets_active ON client_secrets(client_id) WHERE status = 'active';
|
|
67
|
+
|
|
68
|
+
COMMENT ON TABLE client_secrets IS 'Hashed client secrets — multiple active secrets allow zero-downtime rotation';
|
|
69
|
+
COMMENT ON COLUMN client_secrets.secret_hash IS 'Argon2id hash of the client secret (plaintext is never stored)';
|
|
70
|
+
|
|
71
|
+
-- Down Migration
|
|
72
|
+
|
|
73
|
+
DROP TABLE IF EXISTS client_secrets CASCADE;
|
|
74
|
+
DROP TABLE IF EXISTS clients CASCADE;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Users belong to exactly one organization
|
|
4
|
+
-- Profile fields follow OIDC Standard Claims (OpenID Connect Core 1.0, §5.1)
|
|
5
|
+
CREATE TABLE users (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
|
8
|
+
|
|
9
|
+
-- Authentication
|
|
10
|
+
email CITEXT NOT NULL, -- Case-insensitive via citext extension
|
|
11
|
+
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
12
|
+
password_hash TEXT, -- NULL for passwordless-only users
|
|
13
|
+
password_changed_at TIMESTAMPTZ,
|
|
14
|
+
|
|
15
|
+
-- OIDC Standard Claims (OpenID Connect Core 1.0, §5.1)
|
|
16
|
+
given_name VARCHAR(255),
|
|
17
|
+
family_name VARCHAR(255),
|
|
18
|
+
middle_name VARCHAR(255),
|
|
19
|
+
nickname VARCHAR(255),
|
|
20
|
+
preferred_username VARCHAR(255),
|
|
21
|
+
profile_url TEXT, -- "profile" claim
|
|
22
|
+
picture_url TEXT, -- "picture" claim
|
|
23
|
+
website_url TEXT, -- "website" claim
|
|
24
|
+
gender VARCHAR(50),
|
|
25
|
+
birthdate DATE, -- ISO 8601 (YYYY-MM-DD)
|
|
26
|
+
zoneinfo VARCHAR(50), -- e.g., "Europe/Amsterdam"
|
|
27
|
+
locale VARCHAR(10), -- e.g., "nl-NL"
|
|
28
|
+
phone_number VARCHAR(50),
|
|
29
|
+
phone_number_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
30
|
+
|
|
31
|
+
-- Address (structured, OIDC §5.1.1)
|
|
32
|
+
address_street TEXT,
|
|
33
|
+
address_locality VARCHAR(255), -- City
|
|
34
|
+
address_region VARCHAR(255), -- State/Province
|
|
35
|
+
address_postal_code VARCHAR(20),
|
|
36
|
+
address_country VARCHAR(2), -- ISO 3166-1 alpha-2
|
|
37
|
+
|
|
38
|
+
-- Status & Lifecycle
|
|
39
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
40
|
+
CHECK (status IN ('active', 'inactive', 'suspended', 'locked')),
|
|
41
|
+
locked_at TIMESTAMPTZ,
|
|
42
|
+
locked_reason TEXT,
|
|
43
|
+
last_login_at TIMESTAMPTZ,
|
|
44
|
+
login_count INTEGER NOT NULL DEFAULT 0,
|
|
45
|
+
|
|
46
|
+
-- Metadata
|
|
47
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
48
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
49
|
+
|
|
50
|
+
-- Constraints: email is unique per organization (case-insensitive via CITEXT)
|
|
51
|
+
UNIQUE (organization_id, email)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE INDEX idx_users_org ON users(organization_id);
|
|
55
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
56
|
+
CREATE INDEX idx_users_status ON users(organization_id, status);
|
|
57
|
+
|
|
58
|
+
CREATE TRIGGER set_updated_at
|
|
59
|
+
BEFORE UPDATE ON users
|
|
60
|
+
FOR EACH ROW
|
|
61
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
62
|
+
|
|
63
|
+
COMMENT ON TABLE users IS 'User accounts — each user belongs to exactly one organization';
|
|
64
|
+
COMMENT ON COLUMN users.email IS 'Case-insensitive email (CITEXT) — unique per organization';
|
|
65
|
+
COMMENT ON COLUMN users.password_hash IS 'Argon2id hash — NULL for passwordless-only users';
|
|
66
|
+
COMMENT ON COLUMN users.status IS 'User lifecycle: active → inactive/suspended/locked';
|
|
67
|
+
|
|
68
|
+
-- Magic link tokens for passwordless authentication
|
|
69
|
+
CREATE TABLE magic_link_tokens (
|
|
70
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
71
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
72
|
+
token_hash TEXT NOT NULL UNIQUE, -- SHA-256 hash of the token
|
|
73
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
74
|
+
used_at TIMESTAMPTZ, -- NULL = not yet used
|
|
75
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
CREATE INDEX idx_magic_link_user ON magic_link_tokens(user_id);
|
|
79
|
+
CREATE INDEX idx_magic_link_token ON magic_link_tokens(token_hash) WHERE used_at IS NULL;
|
|
80
|
+
|
|
81
|
+
COMMENT ON TABLE magic_link_tokens IS 'Passwordless login tokens — SHA-256 hashed, single-use with expiry';
|
|
82
|
+
|
|
83
|
+
-- Password reset tokens
|
|
84
|
+
CREATE TABLE password_reset_tokens (
|
|
85
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
86
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
87
|
+
token_hash TEXT NOT NULL UNIQUE, -- SHA-256 hash of the token
|
|
88
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
89
|
+
used_at TIMESTAMPTZ,
|
|
90
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX idx_pwd_reset_user ON password_reset_tokens(user_id);
|
|
94
|
+
CREATE INDEX idx_pwd_reset_token ON password_reset_tokens(token_hash) WHERE used_at IS NULL;
|
|
95
|
+
|
|
96
|
+
COMMENT ON TABLE password_reset_tokens IS 'Password reset tokens — SHA-256 hashed, single-use with expiry';
|
|
97
|
+
|
|
98
|
+
-- Invitation tokens — sent when admin creates a user account
|
|
99
|
+
-- User clicks link to set their initial password
|
|
100
|
+
CREATE TABLE invitation_tokens (
|
|
101
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
102
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
103
|
+
token_hash TEXT NOT NULL UNIQUE, -- SHA-256 hash of the token
|
|
104
|
+
expires_at TIMESTAMPTZ NOT NULL, -- Default: 7 days from creation
|
|
105
|
+
used_at TIMESTAMPTZ, -- NULL = not yet accepted
|
|
106
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
CREATE INDEX idx_invitation_user ON invitation_tokens(user_id);
|
|
110
|
+
CREATE INDEX idx_invitation_token ON invitation_tokens(token_hash) WHERE used_at IS NULL;
|
|
111
|
+
|
|
112
|
+
COMMENT ON TABLE invitation_tokens IS 'User invitation tokens — sent by admin, user clicks to set initial password';
|
|
113
|
+
|
|
114
|
+
-- Down Migration
|
|
115
|
+
|
|
116
|
+
DROP TABLE IF EXISTS invitation_tokens CASCADE;
|
|
117
|
+
DROP TABLE IF EXISTS password_reset_tokens CASCADE;
|
|
118
|
+
DROP TABLE IF EXISTS magic_link_tokens CASCADE;
|
|
119
|
+
DROP TABLE IF EXISTS users CASCADE;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Roles are defined globally per application
|
|
4
|
+
-- Role assignments to users are per-organization (since users belong to one org)
|
|
5
|
+
CREATE TABLE roles (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
|
|
8
|
+
name VARCHAR(255) NOT NULL, -- e.g., "CRM Editor"
|
|
9
|
+
slug VARCHAR(100) NOT NULL, -- e.g., "crm-editor"
|
|
10
|
+
description TEXT,
|
|
11
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
12
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
13
|
+
|
|
14
|
+
UNIQUE (application_id, slug)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX idx_roles_application ON roles(application_id);
|
|
18
|
+
|
|
19
|
+
CREATE TRIGGER set_updated_at
|
|
20
|
+
BEFORE UPDATE ON roles
|
|
21
|
+
FOR EACH ROW
|
|
22
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
23
|
+
|
|
24
|
+
COMMENT ON TABLE roles IS 'Global role definitions per application — assigned to users via user_roles';
|
|
25
|
+
|
|
26
|
+
-- Permissions are defined globally per application, optionally scoped to a module
|
|
27
|
+
CREATE TABLE permissions (
|
|
28
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
29
|
+
application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
|
|
30
|
+
module_id UUID REFERENCES application_modules(id) ON DELETE SET NULL,
|
|
31
|
+
name VARCHAR(255) NOT NULL, -- e.g., "Read CRM Contacts"
|
|
32
|
+
slug VARCHAR(150) NOT NULL, -- e.g., "crm:contacts:read"
|
|
33
|
+
description TEXT,
|
|
34
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
35
|
+
|
|
36
|
+
UNIQUE (application_id, slug)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
CREATE INDEX idx_permissions_application ON permissions(application_id);
|
|
40
|
+
CREATE INDEX idx_permissions_module ON permissions(module_id);
|
|
41
|
+
|
|
42
|
+
COMMENT ON TABLE permissions IS 'Global permission definitions per application — optionally scoped to a module';
|
|
43
|
+
COMMENT ON COLUMN permissions.slug IS 'Namespaced permission slug (e.g., "crm:contacts:read")';
|
|
44
|
+
|
|
45
|
+
-- Many-to-many: which permissions does each role grant?
|
|
46
|
+
CREATE TABLE role_permissions (
|
|
47
|
+
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
48
|
+
permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
|
|
49
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
50
|
+
|
|
51
|
+
PRIMARY KEY (role_id, permission_id)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE INDEX idx_role_permissions_role ON role_permissions(role_id);
|
|
55
|
+
CREATE INDEX idx_role_permissions_permission ON role_permissions(permission_id);
|
|
56
|
+
|
|
57
|
+
COMMENT ON TABLE role_permissions IS 'Maps roles to permissions — many-to-many join table';
|
|
58
|
+
|
|
59
|
+
-- Many-to-many: which roles are assigned to each user?
|
|
60
|
+
CREATE TABLE user_roles (
|
|
61
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
62
|
+
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
63
|
+
assigned_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
|
64
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
65
|
+
|
|
66
|
+
PRIMARY KEY (user_id, role_id)
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CREATE INDEX idx_user_roles_user ON user_roles(user_id);
|
|
70
|
+
CREATE INDEX idx_user_roles_role ON user_roles(role_id);
|
|
71
|
+
|
|
72
|
+
COMMENT ON TABLE user_roles IS 'Maps users to roles — includes who assigned the role';
|
|
73
|
+
COMMENT ON COLUMN user_roles.assigned_by IS 'The admin user who assigned this role (NULL if system-assigned)';
|
|
74
|
+
|
|
75
|
+
-- Down Migration
|
|
76
|
+
|
|
77
|
+
DROP TABLE IF EXISTS user_roles CASCADE;
|
|
78
|
+
DROP TABLE IF EXISTS role_permissions CASCADE;
|
|
79
|
+
DROP TABLE IF EXISTS permissions CASCADE;
|
|
80
|
+
DROP TABLE IF EXISTS roles CASCADE;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Custom claim definitions — per application
|
|
4
|
+
-- Controls which tokens include the claim (id_token, access_token, userinfo)
|
|
5
|
+
CREATE TABLE custom_claim_definitions (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
|
|
8
|
+
claim_name VARCHAR(255) NOT NULL, -- e.g., "department"
|
|
9
|
+
claim_type VARCHAR(20) NOT NULL DEFAULT 'string'
|
|
10
|
+
CHECK (claim_type IN ('string', 'number', 'boolean', 'json')),
|
|
11
|
+
description TEXT,
|
|
12
|
+
include_in_id_token BOOLEAN NOT NULL DEFAULT FALSE,
|
|
13
|
+
include_in_access_token BOOLEAN NOT NULL DEFAULT TRUE,
|
|
14
|
+
include_in_userinfo BOOLEAN NOT NULL DEFAULT TRUE,
|
|
15
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
16
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
17
|
+
|
|
18
|
+
UNIQUE (application_id, claim_name)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE INDEX idx_custom_claims_app ON custom_claim_definitions(application_id);
|
|
22
|
+
|
|
23
|
+
CREATE TRIGGER set_updated_at
|
|
24
|
+
BEFORE UPDATE ON custom_claim_definitions
|
|
25
|
+
FOR EACH ROW
|
|
26
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
27
|
+
|
|
28
|
+
COMMENT ON TABLE custom_claim_definitions IS 'Per-application custom claim definitions — controls token inclusion';
|
|
29
|
+
|
|
30
|
+
-- Custom claim values — per user
|
|
31
|
+
-- Stores the actual value as JSONB (supports any type: string, number, boolean, object)
|
|
32
|
+
CREATE TABLE custom_claim_values (
|
|
33
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
34
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
35
|
+
claim_id UUID NOT NULL REFERENCES custom_claim_definitions(id) ON DELETE CASCADE,
|
|
36
|
+
value JSONB NOT NULL, -- Stores any type as JSONB
|
|
37
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
38
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
39
|
+
|
|
40
|
+
UNIQUE (user_id, claim_id)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE INDEX idx_custom_claim_values_user ON custom_claim_values(user_id);
|
|
44
|
+
|
|
45
|
+
CREATE TRIGGER set_updated_at
|
|
46
|
+
BEFORE UPDATE ON custom_claim_values
|
|
47
|
+
FOR EACH ROW
|
|
48
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
49
|
+
|
|
50
|
+
COMMENT ON TABLE custom_claim_values IS 'Per-user custom claim values — JSONB supports any claim type';
|
|
51
|
+
|
|
52
|
+
-- Down Migration
|
|
53
|
+
|
|
54
|
+
DROP TABLE IF EXISTS custom_claim_values CASCADE;
|
|
55
|
+
DROP TABLE IF EXISTS custom_claim_definitions CASCADE;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- System configuration — key-value store with typed JSONB values
|
|
4
|
+
-- All configurable settings (token lifetimes, rate limits, etc.) are stored here
|
|
5
|
+
CREATE TABLE system_config (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
key VARCHAR(255) NOT NULL UNIQUE, -- e.g., "access_token_ttl"
|
|
8
|
+
value JSONB NOT NULL, -- Typed value as JSON
|
|
9
|
+
value_type VARCHAR(20) NOT NULL DEFAULT 'string'
|
|
10
|
+
CHECK (value_type IN ('string', 'number', 'boolean', 'duration', 'json')),
|
|
11
|
+
description TEXT,
|
|
12
|
+
is_sensitive BOOLEAN NOT NULL DEFAULT FALSE, -- Hide from non-super-admin
|
|
13
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
14
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TRIGGER set_updated_at
|
|
18
|
+
BEFORE UPDATE ON system_config
|
|
19
|
+
FOR EACH ROW
|
|
20
|
+
EXECUTE FUNCTION trigger_set_updated_at();
|
|
21
|
+
|
|
22
|
+
COMMENT ON TABLE system_config IS 'System-wide configuration — key-value store with typed JSONB values';
|
|
23
|
+
COMMENT ON COLUMN system_config.is_sensitive IS 'If true, value is hidden from non-super-admin users';
|
|
24
|
+
|
|
25
|
+
-- Signing keys for JWKS (JSON Web Key Sets)
|
|
26
|
+
-- Stores PEM-encoded key pairs with lifecycle management
|
|
27
|
+
CREATE TABLE signing_keys (
|
|
28
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
29
|
+
kid VARCHAR(255) NOT NULL UNIQUE, -- Key ID (for JWKS)
|
|
30
|
+
algorithm VARCHAR(10) NOT NULL DEFAULT 'ES256',
|
|
31
|
+
public_key TEXT NOT NULL, -- PEM-encoded public key
|
|
32
|
+
private_key TEXT NOT NULL, -- PEM-encoded private key (encrypted at rest)
|
|
33
|
+
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
|
34
|
+
CHECK (status IN ('active', 'retired', 'revoked')),
|
|
35
|
+
activated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
36
|
+
retired_at TIMESTAMPTZ, -- When marked as retired
|
|
37
|
+
expires_at TIMESTAMPTZ, -- Grace period expiry
|
|
38
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX idx_signing_keys_status ON signing_keys(status);
|
|
42
|
+
CREATE INDEX idx_signing_keys_active ON signing_keys(status) WHERE status = 'active';
|
|
43
|
+
|
|
44
|
+
COMMENT ON TABLE signing_keys IS 'JWKS signing key pairs — supports key rotation with active/retired/revoked lifecycle';
|
|
45
|
+
COMMENT ON COLUMN signing_keys.kid IS 'Key ID published in JWKS endpoint for token verification';
|
|
46
|
+
COMMENT ON COLUMN signing_keys.private_key IS 'PEM-encoded private key — should be encrypted at rest in production';
|
|
47
|
+
|
|
48
|
+
-- Down Migration
|
|
49
|
+
|
|
50
|
+
DROP TABLE IF EXISTS signing_keys CASCADE;
|
|
51
|
+
DROP TABLE IF EXISTS system_config CASCADE;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Audit log for security events
|
|
4
|
+
-- Uses SET NULL on delete to preserve audit entries when users/orgs are removed
|
|
5
|
+
CREATE TABLE audit_log (
|
|
6
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
organization_id UUID REFERENCES organizations(id) ON DELETE SET NULL,
|
|
8
|
+
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
|
9
|
+
actor_id UUID REFERENCES users(id) ON DELETE SET NULL, -- Who performed the action
|
|
10
|
+
event_type VARCHAR(100) NOT NULL, -- e.g., "user.login.success"
|
|
11
|
+
event_category VARCHAR(50) NOT NULL, -- e.g., "authentication", "admin", "security"
|
|
12
|
+
description TEXT,
|
|
13
|
+
metadata JSONB DEFAULT '{}', -- Additional context (IP, user-agent, etc.)
|
|
14
|
+
ip_address INET,
|
|
15
|
+
user_agent TEXT,
|
|
16
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- Composite indexes for common query patterns (org+time, user+time, event+time)
|
|
20
|
+
CREATE INDEX idx_audit_log_org ON audit_log(organization_id, created_at DESC);
|
|
21
|
+
CREATE INDEX idx_audit_log_user ON audit_log(user_id, created_at DESC);
|
|
22
|
+
CREATE INDEX idx_audit_log_event ON audit_log(event_type, created_at DESC);
|
|
23
|
+
CREATE INDEX idx_audit_log_category ON audit_log(event_category, created_at DESC);
|
|
24
|
+
|
|
25
|
+
COMMENT ON TABLE audit_log IS 'Security event audit log — append-only, preserved on user/org deletion';
|
|
26
|
+
COMMENT ON COLUMN audit_log.actor_id IS 'The user who performed the action (may differ from user_id for admin actions)';
|
|
27
|
+
COMMENT ON COLUMN audit_log.metadata IS 'Structured additional context (e.g., IP address, user-agent, request details)';
|
|
28
|
+
|
|
29
|
+
-- Down Migration
|
|
30
|
+
|
|
31
|
+
DROP TABLE IF EXISTS audit_log CASCADE;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Generic OIDC adapter storage table for node-oidc-provider
|
|
4
|
+
-- Stores: AccessToken, AuthorizationCode, RefreshToken, DeviceCode,
|
|
5
|
+
-- ClientCredentials, InitialAccessToken, RegistrationAccessToken,
|
|
6
|
+
-- Interaction, ReplayDetection, PushedAuthorizationRequest, Grant,
|
|
7
|
+
-- Session, BackchannelAuthenticationRequest
|
|
8
|
+
CREATE TABLE oidc_payloads (
|
|
9
|
+
id VARCHAR(255) NOT NULL,
|
|
10
|
+
type VARCHAR(50) NOT NULL, -- Model name (e.g., "AccessToken")
|
|
11
|
+
payload JSONB NOT NULL,
|
|
12
|
+
grant_id VARCHAR(255),
|
|
13
|
+
user_code VARCHAR(255),
|
|
14
|
+
uid VARCHAR(255),
|
|
15
|
+
expires_at TIMESTAMPTZ,
|
|
16
|
+
consumed_at TIMESTAMPTZ,
|
|
17
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
18
|
+
|
|
19
|
+
PRIMARY KEY (id, type)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- Partial indexes for efficient lookups on non-null columns
|
|
23
|
+
CREATE INDEX idx_oidc_payloads_grant ON oidc_payloads(grant_id) WHERE grant_id IS NOT NULL;
|
|
24
|
+
CREATE INDEX idx_oidc_payloads_user_code ON oidc_payloads(user_code) WHERE user_code IS NOT NULL;
|
|
25
|
+
CREATE INDEX idx_oidc_payloads_uid ON oidc_payloads(uid) WHERE uid IS NOT NULL;
|
|
26
|
+
CREATE INDEX idx_oidc_payloads_expires ON oidc_payloads(expires_at) WHERE expires_at IS NOT NULL;
|
|
27
|
+
|
|
28
|
+
COMMENT ON TABLE oidc_payloads IS 'Generic storage for node-oidc-provider — all OIDC artifact types share this table';
|
|
29
|
+
COMMENT ON COLUMN oidc_payloads.type IS 'OIDC model type (e.g., AccessToken, AuthorizationCode, Session)';
|
|
30
|
+
COMMENT ON COLUMN oidc_payloads.payload IS 'Full OIDC artifact payload as JSONB';
|
|
31
|
+
|
|
32
|
+
-- Down Migration
|
|
33
|
+
|
|
34
|
+
DROP TABLE IF EXISTS oidc_payloads CASCADE;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Seed data for development: super-admin organization and default system config values.
|
|
4
|
+
-- NOTE: Super-admin user is NOT created here (deferred to RD-06, requires password hashing).
|
|
5
|
+
-- NOTE: Signing keys are NOT created here (deferred to RD-03, requires crypto key generation).
|
|
6
|
+
|
|
7
|
+
-- Super-admin organization
|
|
8
|
+
-- The is_super_admin partial unique index ensures only one row can have is_super_admin = TRUE
|
|
9
|
+
INSERT INTO organizations (name, slug, status, is_super_admin, branding_company_name, default_locale)
|
|
10
|
+
VALUES ('Porta Admin', 'porta-admin', 'active', TRUE, 'Porta', 'en');
|
|
11
|
+
|
|
12
|
+
-- Default system configuration values
|
|
13
|
+
-- These control global OIDC/auth behavior and can be changed at runtime via admin UI
|
|
14
|
+
INSERT INTO system_config (key, value, value_type, description, is_sensitive) VALUES
|
|
15
|
+
-- Token lifetimes
|
|
16
|
+
('access_token_ttl', '"3600"', 'duration', 'Access token TTL in seconds (default: 1 hour)', FALSE),
|
|
17
|
+
('id_token_ttl', '"3600"', 'duration', 'ID token TTL in seconds (default: 1 hour)', FALSE),
|
|
18
|
+
('refresh_token_ttl', '"2592000"', 'duration', 'Refresh token TTL in seconds (default: 30 days)', FALSE),
|
|
19
|
+
('authorization_code_ttl', '"600"', 'duration', 'Authorization code TTL in seconds (default: 10 minutes)', FALSE),
|
|
20
|
+
|
|
21
|
+
-- Session settings
|
|
22
|
+
('session_ttl', '"86400"', 'duration', 'Session TTL in seconds (default: 24 hours)', FALSE),
|
|
23
|
+
('cookie_secure', 'true', 'boolean', 'Require HTTPS for cookies (disable for local dev only)', FALSE),
|
|
24
|
+
|
|
25
|
+
-- Magic link / passwordless
|
|
26
|
+
('magic_link_ttl', '"900"', 'duration', 'Magic link token TTL in seconds (default: 15 minutes)', FALSE),
|
|
27
|
+
('magic_link_length', '48', 'number', 'Magic link token length in bytes', FALSE),
|
|
28
|
+
|
|
29
|
+
-- Password reset
|
|
30
|
+
('password_reset_ttl', '"3600"', 'duration', 'Password reset token TTL in seconds (default: 1 hour)', FALSE),
|
|
31
|
+
|
|
32
|
+
-- Invitation
|
|
33
|
+
('invitation_ttl', '"604800"', 'duration', 'Invitation token TTL in seconds (default: 7 days)', FALSE),
|
|
34
|
+
|
|
35
|
+
-- Rate limiting
|
|
36
|
+
('login_rate_limit', '10', 'number', 'Max login attempts per user per 15 minutes', FALSE),
|
|
37
|
+
('api_rate_limit', '100', 'number', 'Max API requests per client per minute', FALSE),
|
|
38
|
+
|
|
39
|
+
-- Account lockout
|
|
40
|
+
('max_failed_logins', '5', 'number', 'Max failed logins before account lockout', FALSE),
|
|
41
|
+
('lockout_duration', '"900"', 'duration', 'Account lockout duration in seconds (default: 15 minutes)', FALSE),
|
|
42
|
+
|
|
43
|
+
-- PKCE
|
|
44
|
+
('require_pkce', 'true', 'boolean', 'Require PKCE for all authorization code flows', FALSE),
|
|
45
|
+
|
|
46
|
+
-- CORS
|
|
47
|
+
('cors_max_age', '86400', 'number', 'CORS preflight cache duration in seconds (default: 24h)', FALSE);
|
|
48
|
+
|
|
49
|
+
-- Down Migration
|
|
50
|
+
|
|
51
|
+
-- Remove seed data in reverse order
|
|
52
|
+
DELETE FROM system_config;
|
|
53
|
+
DELETE FROM organizations WHERE slug = 'porta-admin';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
-- Up Migration
|
|
2
|
+
|
|
3
|
+
-- Two-Factor Authentication (RD-12)
|
|
4
|
+
-- Adds per-org 2FA policy, per-user 2FA state, and tables for TOTP config,
|
|
5
|
+
-- email OTP codes, and recovery codes.
|
|
6
|
+
|
|
7
|
+
-- Add 2FA policy to organizations — controls whether 2FA is required for org members.
|
|
8
|
+
-- Values: 'optional' (default), 'required_email', 'required_totp', 'required_any'
|
|
9
|
+
ALTER TABLE organizations
|
|
10
|
+
ADD COLUMN two_factor_policy VARCHAR(20) NOT NULL DEFAULT 'optional'
|
|
11
|
+
CHECK (two_factor_policy IN ('optional', 'required_email', 'required_totp', 'required_any'));
|
|
12
|
+
|
|
13
|
+
-- Add 2FA state columns to users — tracks whether 2FA is enabled and which method.
|
|
14
|
+
ALTER TABLE users
|
|
15
|
+
ADD COLUMN two_factor_enabled BOOLEAN NOT NULL DEFAULT false,
|
|
16
|
+
ADD COLUMN two_factor_method VARCHAR(10) DEFAULT NULL
|
|
17
|
+
CHECK (two_factor_method IN ('email', 'totp') OR two_factor_method IS NULL);
|
|
18
|
+
|
|
19
|
+
-- TOTP configuration per user (encrypted secrets)
|
|
20
|
+
-- Stores AES-256-GCM encrypted TOTP secret, one row per user.
|
|
21
|
+
CREATE TABLE user_totp (
|
|
22
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
23
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
24
|
+
encrypted_secret TEXT NOT NULL, -- AES-256-GCM encrypted TOTP secret
|
|
25
|
+
encryption_iv TEXT NOT NULL, -- Initialization vector (hex)
|
|
26
|
+
encryption_tag TEXT NOT NULL, -- Authentication tag (hex)
|
|
27
|
+
algorithm VARCHAR(10) NOT NULL DEFAULT 'SHA1',
|
|
28
|
+
digits INTEGER NOT NULL DEFAULT 6,
|
|
29
|
+
period INTEGER NOT NULL DEFAULT 30,
|
|
30
|
+
verified BOOLEAN NOT NULL DEFAULT false, -- true after first successful TOTP verification
|
|
31
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
32
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
33
|
+
UNIQUE (user_id) -- one TOTP config per user
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
-- Email OTP codes (SHA-256 hashed, short-lived)
|
|
37
|
+
-- Stores hashed 6-digit codes sent via email for 2FA verification.
|
|
38
|
+
CREATE TABLE two_factor_otp_codes (
|
|
39
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
40
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
41
|
+
code_hash VARCHAR(64) NOT NULL, -- SHA-256 hex hash of 6-digit code
|
|
42
|
+
expires_at TIMESTAMPTZ NOT NULL, -- 10 minute expiry
|
|
43
|
+
used_at TIMESTAMPTZ DEFAULT NULL, -- NULL = unused, set on successful verification
|
|
44
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
-- Index for fast lookup of active (unused, not expired) OTP codes per user
|
|
48
|
+
CREATE INDEX idx_otp_codes_user_active
|
|
49
|
+
ON two_factor_otp_codes(user_id, expires_at)
|
|
50
|
+
WHERE used_at IS NULL;
|
|
51
|
+
|
|
52
|
+
-- Recovery codes (Argon2id hashed, single-use)
|
|
53
|
+
-- 10 codes generated during 2FA setup, each usable once as a backup.
|
|
54
|
+
CREATE TABLE two_factor_recovery_codes (
|
|
55
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
56
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
57
|
+
code_hash TEXT NOT NULL, -- Argon2id hash of recovery code
|
|
58
|
+
used_at TIMESTAMPTZ DEFAULT NULL, -- NULL = unused
|
|
59
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
-- Index for fast lookup of unused recovery codes per user
|
|
63
|
+
CREATE INDEX idx_recovery_codes_user
|
|
64
|
+
ON two_factor_recovery_codes(user_id)
|
|
65
|
+
WHERE used_at IS NULL;
|
|
66
|
+
|
|
67
|
+
-- Auto-update trigger for user_totp.updated_at
|
|
68
|
+
-- Uses the reusable trigger function defined in 001_extensions.sql
|
|
69
|
+
CREATE TRIGGER set_user_totp_updated_at
|
|
70
|
+
BEFORE UPDATE ON user_totp
|
|
71
|
+
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
|
|
72
|
+
|
|
73
|
+
-- Down Migration
|
|
74
|
+
|
|
75
|
+
-- Drop tables and indexes (indexes are dropped automatically with tables)
|
|
76
|
+
DROP TRIGGER IF EXISTS set_user_totp_updated_at ON user_totp;
|
|
77
|
+
DROP TABLE IF EXISTS two_factor_recovery_codes;
|
|
78
|
+
DROP TABLE IF EXISTS two_factor_otp_codes;
|
|
79
|
+
DROP TABLE IF EXISTS user_totp;
|
|
80
|
+
|
|
81
|
+
-- Remove 2FA columns from users
|
|
82
|
+
ALTER TABLE users
|
|
83
|
+
DROP COLUMN IF EXISTS two_factor_method,
|
|
84
|
+
DROP COLUMN IF EXISTS two_factor_enabled;
|
|
85
|
+
|
|
86
|
+
-- Remove 2FA policy from organizations
|
|
87
|
+
ALTER TABLE organizations
|
|
88
|
+
DROP COLUMN IF EXISTS two_factor_policy;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- Migration 013: Add SHA-256 hash column to client_secrets
|
|
2
|
+
--
|
|
3
|
+
-- Adds a SHA-256 hex hash column used for oidc-provider client authentication.
|
|
4
|
+
-- SHA-256 is appropriate for machine-generated, high-entropy client secrets
|
|
5
|
+
-- (48 bytes / 384 bits). Argon2id hashes are retained for admin API verification.
|
|
6
|
+
--
|
|
7
|
+
-- Existing secrets cannot be backfilled (we don't have plaintexts).
|
|
8
|
+
-- New secrets will have both Argon2id hash and SHA-256 hash.
|
|
9
|
+
|
|
10
|
+
-- Up Migration
|
|
11
|
+
ALTER TABLE client_secrets ADD COLUMN secret_sha256 VARCHAR(64);
|
|
12
|
+
|
|
13
|
+
CREATE INDEX idx_client_secrets_sha256
|
|
14
|
+
ON client_secrets(secret_sha256)
|
|
15
|
+
WHERE secret_sha256 IS NOT NULL;
|
|
16
|
+
|
|
17
|
+
COMMENT ON COLUMN client_secrets.secret_sha256
|
|
18
|
+
IS 'SHA-256 hex hash of the secret — used for oidc-provider client authentication';
|
|
19
|
+
|
|
20
|
+
-- Down Migration (in comments for reference)
|
|
21
|
+
-- DROP INDEX IF EXISTS idx_client_secrets_sha256;
|
|
22
|
+
-- ALTER TABLE client_secrets DROP COLUMN IF EXISTS secret_sha256;
|