@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,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OIDC CORS middleware — pre-sets CORS headers at the outer Koa level.
|
|
3
|
+
*
|
|
4
|
+
* Solves a fundamental issue with node-oidc-provider's CORS handling:
|
|
5
|
+
* the provider uses @koa/cors with `keepHeadersOnError: false`, which
|
|
6
|
+
* means CORS headers are stripped from error responses (e.g., 400 from
|
|
7
|
+
* the token endpoint). SPAs that exchange authorization codes or refresh
|
|
8
|
+
* tokens via cross-origin fetch() cannot read error responses, breaking
|
|
9
|
+
* error handling in browser-based OIDC flows.
|
|
10
|
+
*
|
|
11
|
+
* How this middleware fixes it:
|
|
12
|
+
*
|
|
13
|
+
* 1. It sets `Access-Control-Allow-Origin` and related headers BEFORE
|
|
14
|
+
* the request enters oidc-provider's internal Koa context.
|
|
15
|
+
*
|
|
16
|
+
* 2. The provider's `cors.js` middleware detects existing `access-control-*`
|
|
17
|
+
* headers and SKIPS its own CORS handling entirely (see
|
|
18
|
+
* node_modules/oidc-provider/lib/shared/cors.js lines 32-37).
|
|
19
|
+
*
|
|
20
|
+
* 3. Because the headers are set at the outer Koa level and the provider
|
|
21
|
+
* doesn't touch them, they survive regardless of whether the OIDC
|
|
22
|
+
* endpoint succeeds or returns an error.
|
|
23
|
+
*
|
|
24
|
+
* Origin validation follows the same two-tier strategy as `oidc-cors.ts`:
|
|
25
|
+
* - In development mode: all origins are allowed.
|
|
26
|
+
* - In production: the client's `allowed_origins` and `redirect_uris`
|
|
27
|
+
* are checked. The client is identified from the `client_id` body
|
|
28
|
+
* parameter (standard for token, revocation, and introspection
|
|
29
|
+
* endpoints). If no client_id is present or the client cannot be
|
|
30
|
+
* found, no CORS headers are set — the request proceeds but the
|
|
31
|
+
* browser will block the response (correct security behavior).
|
|
32
|
+
*
|
|
33
|
+
* Placement: mount in the `oidcRouter` (server.ts) AFTER the body parser
|
|
34
|
+
* (so `client_id` is available from `ctx.request.body`) but BEFORE the
|
|
35
|
+
* `clientSecretHash` middleware and the provider delegation handler.
|
|
36
|
+
*
|
|
37
|
+
* For OIDC endpoints that don't require client authentication (e.g.,
|
|
38
|
+
* JWKS, discovery), CORS is always allowed — these are public endpoints
|
|
39
|
+
* that any origin may access. The middleware detects these by path.
|
|
40
|
+
*
|
|
41
|
+
* @module middleware/oidc-preflight-cors
|
|
42
|
+
*/
|
|
43
|
+
import { config } from '../config/index.js';
|
|
44
|
+
import { getClientByClientId } from '../clients/service.js';
|
|
45
|
+
import { getPool } from '../lib/database.js';
|
|
46
|
+
import { logger } from '../lib/logger.js';
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Public-endpoint path patterns — these are accessible without client auth
|
|
49
|
+
// and allow CORS from any origin (same as oidc-provider's "open" CORS).
|
|
50
|
+
// Paths are relative to the /:orgSlug prefix (after tenant resolution).
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/** Paths that are publicly accessible and allow any CORS origin. */
|
|
53
|
+
const OPEN_CORS_PATHS = new Set([
|
|
54
|
+
'/jwks',
|
|
55
|
+
'/.well-known/openid-configuration',
|
|
56
|
+
'/.well-known/oauth-authorization-server',
|
|
57
|
+
]);
|
|
58
|
+
/**
|
|
59
|
+
* Check if the request path (within the org scope) is a public endpoint
|
|
60
|
+
* that allows CORS from any origin.
|
|
61
|
+
*
|
|
62
|
+
* @param fullPath - The full request path (e.g., '/acme/jwks')
|
|
63
|
+
* @param orgSlug - The organization slug (e.g., 'acme')
|
|
64
|
+
* @returns true if the path is a public CORS endpoint
|
|
65
|
+
*/
|
|
66
|
+
function isOpenCorsPath(fullPath, orgSlug) {
|
|
67
|
+
const subPath = fullPath.slice(`/${orgSlug}`.length);
|
|
68
|
+
return OPEN_CORS_PATHS.has(subPath);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if an origin is allowed for a given client by examining the
|
|
72
|
+
* client's `allowedOrigins` and `redirectUris` fields.
|
|
73
|
+
*
|
|
74
|
+
* This replicates the same logic as `oidc-cors.ts` but works with the
|
|
75
|
+
* Client domain object (from the service layer) rather than the OIDC
|
|
76
|
+
* provider's internal client metadata format.
|
|
77
|
+
*
|
|
78
|
+
* @param origin - The requesting origin (e.g., 'https://app.example.com')
|
|
79
|
+
* @param client - Client with allowedOrigins and redirectUris arrays
|
|
80
|
+
* @returns true if the origin is allowed
|
|
81
|
+
*/
|
|
82
|
+
function isOriginAllowed(origin, client) {
|
|
83
|
+
// 1. Check explicit allowed_origins
|
|
84
|
+
if (client.allowedOrigins.includes(origin))
|
|
85
|
+
return true;
|
|
86
|
+
// 2. Derive origins from redirect_uris
|
|
87
|
+
for (const uri of client.redirectUris) {
|
|
88
|
+
try {
|
|
89
|
+
const redirectOrigin = new URL(uri).origin;
|
|
90
|
+
if (redirectOrigin !== 'null' && redirectOrigin === origin)
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Skip malformed URIs
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Set standard CORS response headers for an allowed origin.
|
|
101
|
+
*
|
|
102
|
+
* @param ctx - Koa context
|
|
103
|
+
* @param origin - The allowed origin value
|
|
104
|
+
*/
|
|
105
|
+
function setCorsHeaders(ctx, origin) {
|
|
106
|
+
ctx.set('Access-Control-Allow-Origin', origin);
|
|
107
|
+
ctx.set('Vary', 'Origin');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Set preflight-specific CORS response headers (in addition to the base
|
|
111
|
+
* headers set by `setCorsHeaders`).
|
|
112
|
+
*
|
|
113
|
+
* @param ctx - Koa context
|
|
114
|
+
*/
|
|
115
|
+
function setPreflightHeaders(ctx) {
|
|
116
|
+
ctx.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
117
|
+
ctx.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, DPoP');
|
|
118
|
+
ctx.set('Access-Control-Max-Age', '3600');
|
|
119
|
+
}
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Bearer token → clientId resolution
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
/**
|
|
124
|
+
* Extract the `clientId` from an opaque Bearer access token by looking
|
|
125
|
+
* up its record in PostgreSQL.
|
|
126
|
+
*
|
|
127
|
+
* node-oidc-provider stores opaque access tokens in the `oidc_payloads`
|
|
128
|
+
* table (via the PostgresAdapter) with `type = 'AccessToken'`. The token
|
|
129
|
+
* value sent by the client IS the `jti`, which is the `id` column in the
|
|
130
|
+
* table. The JSONB `payload` column includes a `clientId` field.
|
|
131
|
+
*
|
|
132
|
+
* NOTE: AccessToken is a long-lived model routed to PostgreSQL by the
|
|
133
|
+
* hybrid adapter factory (adapter-factory.ts). Short-lived models like
|
|
134
|
+
* Session and AuthorizationCode go to Redis, but AccessToken does NOT.
|
|
135
|
+
*
|
|
136
|
+
* This lookup is best-effort: if the token is missing, expired, or the
|
|
137
|
+
* database is unavailable, `null` is returned and CORS headers are not
|
|
138
|
+
* set. The actual token validation is still performed by the provider
|
|
139
|
+
* downstream.
|
|
140
|
+
*
|
|
141
|
+
* @param authHeader - The raw `Authorization` header value (e.g., 'Bearer abc123')
|
|
142
|
+
* @returns The clientId if resolved, or null
|
|
143
|
+
*/
|
|
144
|
+
async function resolveClientIdFromBearerToken(authHeader) {
|
|
145
|
+
if (!authHeader)
|
|
146
|
+
return null;
|
|
147
|
+
// Extract the token value from "Bearer <token>"
|
|
148
|
+
const match = /^Bearer\s+(\S+)$/i.exec(authHeader);
|
|
149
|
+
if (!match)
|
|
150
|
+
return null;
|
|
151
|
+
const tokenValue = match[1];
|
|
152
|
+
try {
|
|
153
|
+
const pool = getPool();
|
|
154
|
+
const result = await pool.query(`SELECT payload->>'clientId' AS client_id
|
|
155
|
+
FROM oidc_payloads
|
|
156
|
+
WHERE id = $1 AND type = 'AccessToken'
|
|
157
|
+
AND (expires_at IS NULL OR expires_at > NOW())`, [tokenValue]);
|
|
158
|
+
if (result.rows.length === 0)
|
|
159
|
+
return null;
|
|
160
|
+
const clientId = result.rows[0].client_id;
|
|
161
|
+
return typeof clientId === 'string' && clientId.length > 0 ? clientId : null;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// Database unavailable — graceful degradation.
|
|
165
|
+
// The provider will still validate the token; we just can't set
|
|
166
|
+
// CORS headers pre-emptively.
|
|
167
|
+
logger.debug({ err }, 'OIDC CORS: failed to resolve clientId from Bearer token');
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// Middleware factory
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
/**
|
|
175
|
+
* Create the OIDC CORS middleware.
|
|
176
|
+
*
|
|
177
|
+
* Must be mounted in the oidcRouter AFTER the body parser (so
|
|
178
|
+
* `client_id` is available) but BEFORE `clientSecretHash` and the
|
|
179
|
+
* provider delegation handler.
|
|
180
|
+
*
|
|
181
|
+
* @returns Koa middleware that pre-sets CORS headers for OIDC routes
|
|
182
|
+
*/
|
|
183
|
+
export function oidcPreflightCors() {
|
|
184
|
+
return async function oidcPreflightCorsMiddleware(ctx, next) {
|
|
185
|
+
const origin = ctx.get('Origin');
|
|
186
|
+
// No Origin header → not a CORS request (backend service, curl, etc.)
|
|
187
|
+
// Skip — no CORS headers needed.
|
|
188
|
+
if (!origin) {
|
|
189
|
+
return next();
|
|
190
|
+
}
|
|
191
|
+
const orgSlug = ctx.params?.orgSlug ?? '';
|
|
192
|
+
// -----------------------------------------------------------------------
|
|
193
|
+
// OPTIONS preflight — respond immediately, skip downstream middleware
|
|
194
|
+
// -----------------------------------------------------------------------
|
|
195
|
+
if (ctx.method === 'OPTIONS') {
|
|
196
|
+
// Dev: allow all origins
|
|
197
|
+
// Prod: allow preflight broadly — the actual request will do the
|
|
198
|
+
// full client-based check. If the actual request's origin is
|
|
199
|
+
// unauthorized, it won't have CORS headers and the browser will
|
|
200
|
+
// block the response. This is secure because the preflight itself
|
|
201
|
+
// doesn't grant any access — it only tells the browser that a
|
|
202
|
+
// subsequent actual request is permitted to be sent.
|
|
203
|
+
setCorsHeaders(ctx, origin);
|
|
204
|
+
setPreflightHeaders(ctx);
|
|
205
|
+
ctx.status = 204;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
// -----------------------------------------------------------------------
|
|
209
|
+
// Actual request (GET, POST, etc.) with Origin header
|
|
210
|
+
// -----------------------------------------------------------------------
|
|
211
|
+
// Public endpoints (jwks, discovery) allow any origin — no client check.
|
|
212
|
+
if (isOpenCorsPath(ctx.path, orgSlug)) {
|
|
213
|
+
setCorsHeaders(ctx, origin);
|
|
214
|
+
return next();
|
|
215
|
+
}
|
|
216
|
+
// Development mode: allow all origins for convenience.
|
|
217
|
+
if (config.nodeEnv === 'development') {
|
|
218
|
+
setCorsHeaders(ctx, origin);
|
|
219
|
+
return next();
|
|
220
|
+
}
|
|
221
|
+
// Production mode: client-based CORS check.
|
|
222
|
+
// Strategy: identify the client from one of two sources, then check
|
|
223
|
+
// whether the requesting origin is allowed for that client.
|
|
224
|
+
//
|
|
225
|
+
// 1. `client_id` in the body — token, revocation, introspection
|
|
226
|
+
// endpoints send client_id in the form-encoded body.
|
|
227
|
+
// 2. Bearer token in `Authorization` header — userinfo (/me) and
|
|
228
|
+
// other authenticated GET endpoints. The access token record in
|
|
229
|
+
// PostgreSQL contains the clientId that issued it.
|
|
230
|
+
//
|
|
231
|
+
// If neither source yields a client, no CORS headers are set (safe
|
|
232
|
+
// default: browser blocks the cross-origin response).
|
|
233
|
+
const body = ctx.request.body;
|
|
234
|
+
let clientId = typeof body?.client_id === 'string' && body.client_id.length > 0
|
|
235
|
+
? body.client_id
|
|
236
|
+
: null;
|
|
237
|
+
// Fallback: extract clientId from a Bearer access token stored in PostgreSQL.
|
|
238
|
+
// This enables CORS for endpoints like /me (userinfo) where the only
|
|
239
|
+
// client identifier is embedded in the opaque access token record.
|
|
240
|
+
if (!clientId) {
|
|
241
|
+
clientId = await resolveClientIdFromBearerToken(ctx.get('Authorization'));
|
|
242
|
+
}
|
|
243
|
+
if (!clientId) {
|
|
244
|
+
// Can't identify client from body or Bearer token — skip CORS.
|
|
245
|
+
// The provider will process the request, but the browser blocks
|
|
246
|
+
// the cross-origin response. This is correct security behavior.
|
|
247
|
+
return next();
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const client = await getClientByClientId(clientId);
|
|
251
|
+
if (client && isOriginAllowed(origin, client)) {
|
|
252
|
+
setCorsHeaders(ctx, origin);
|
|
253
|
+
}
|
|
254
|
+
// If client not found or origin not allowed, don't set CORS headers.
|
|
255
|
+
// The provider processes the request normally, but the browser blocks
|
|
256
|
+
// the cross-origin response — correct security behavior.
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
// Graceful degradation: if the client lookup fails (e.g., DB down),
|
|
260
|
+
// don't set CORS headers. The request proceeds but the browser
|
|
261
|
+
// blocks the response. This is the safe default.
|
|
262
|
+
logger.warn({ err, clientId, origin }, 'OIDC CORS: client lookup failed, CORS headers not set');
|
|
263
|
+
}
|
|
264
|
+
return next();
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=oidc-preflight-cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-preflight-cors.js","sourceRoot":"","sources":["../../src/middleware/oidc-preflight-cors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt=login session-reset middleware.
|
|
3
|
+
*
|
|
4
|
+
* Fixes the "Something went wrong" dead-end on browser re-login (Bug #1).
|
|
5
|
+
*
|
|
6
|
+
* Root cause: a stale `_session` cookie from a previous login survives into a
|
|
7
|
+
* new `prompt=login` authorization flow. The provider rotates the session id
|
|
8
|
+
* during resume, so the interaction's recorded session uid no longer matches
|
|
9
|
+
* the live session uid → node-oidc-provider throws `SessionNotFound` and the
|
|
10
|
+
* user sees a terminal error. (Confirmed: the Redis Session record is present
|
|
11
|
+
* during the failure — this is NOT a Redis durability problem.)
|
|
12
|
+
*
|
|
13
|
+
* Fix: on an initial GET/POST authorize request whose `prompt` parameter
|
|
14
|
+
* contains `login`, clear the `_session` + `_session.sig` cookies BEFORE the
|
|
15
|
+
* provider runs. With no stale cookie, the provider mints a fresh session and
|
|
16
|
+
* there is no uid mismatch. The stale Redis Session record is left to expire on
|
|
17
|
+
* its own via TTL (AR-2, revised) — clearing the cookie is what fixes the bug.
|
|
18
|
+
*
|
|
19
|
+
* Design notes:
|
|
20
|
+
* - Only acts when `prompt` contains the `login` value (AR-3). Normal SSO /
|
|
21
|
+
* session-reuse logins are unaffected (AR-5).
|
|
22
|
+
* - Reads `prompt` from the query string. The CLI and standard browser RP flows
|
|
23
|
+
* use GET authorize with `prompt` in the query, so this covers the real flow
|
|
24
|
+
* without consuming the POST body stream the provider needs (PF-005).
|
|
25
|
+
* - Cookie clearing is signing-free: we expire both `_session` and
|
|
26
|
+
* `_session.sig` explicitly. The outer Koa app does not set `app.keys`, so we
|
|
27
|
+
* must NOT rely on Koa's signed-cookie API here (PF-001/PF-002).
|
|
28
|
+
*
|
|
29
|
+
* @module middleware/prompt-login-reset
|
|
30
|
+
*/
|
|
31
|
+
import type { Middleware } from 'koa';
|
|
32
|
+
import type Provider from 'oidc-provider';
|
|
33
|
+
/**
|
|
34
|
+
* Does the OIDC `prompt` parameter request a forced login?
|
|
35
|
+
*
|
|
36
|
+
* Per OIDC Core §3.1.2.1, `prompt` is a space-delimited list of values.
|
|
37
|
+
* Returns true only when `login` is one of those values (exact token match —
|
|
38
|
+
* not a substring, so `logins` or `login_hint` values do not match).
|
|
39
|
+
*
|
|
40
|
+
* @param prompt - The raw `prompt` parameter value (or undefined)
|
|
41
|
+
* @returns true if `login` is present among the space-delimited values
|
|
42
|
+
*/
|
|
43
|
+
export declare function promptHasLogin(prompt: string | undefined | null): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Is this request the INITIAL org-scoped authorize endpoint?
|
|
46
|
+
*
|
|
47
|
+
* Matches `GET`/`POST` `/{orgSlug}/auth` (with optional trailing slash) but
|
|
48
|
+
* NOT the resume route `/{orgSlug}/auth/{uid}` and not other OIDC endpoints
|
|
49
|
+
* (`/token`, `/jwks`, etc.). The resume route must be excluded because the
|
|
50
|
+
* session-mismatch happens there — we reset on the *initial* authorize so the
|
|
51
|
+
* interaction binds to a fresh session.
|
|
52
|
+
*
|
|
53
|
+
* @param method - HTTP method
|
|
54
|
+
* @param path - Request path (outer Koa path, includes the org slug)
|
|
55
|
+
* @returns true if this is the initial authorize endpoint
|
|
56
|
+
*/
|
|
57
|
+
export declare function isInitialAuthorize(method: string, path: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Clear the OIDC session cookie pair (`_session` + `_session.sig`).
|
|
60
|
+
*
|
|
61
|
+
* Expires BOTH cookie names at path `/` with attributes matching how the
|
|
62
|
+
* provider wrote them (httpOnly, sameSite=lax, secure per issuer scheme). This
|
|
63
|
+
* is intentionally signing-free: it sets each cookie to an expired value
|
|
64
|
+
* directly, so it works regardless of whether `app.keys` is configured on the
|
|
65
|
+
* Koa app (the outer Porta app does not set it). (PF-001/PF-002, AR-2)
|
|
66
|
+
*
|
|
67
|
+
* @param ctx - Koa context (outer app context or provider ctx — both work)
|
|
68
|
+
* @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
|
|
69
|
+
*/
|
|
70
|
+
export declare function clearSessionCookies(ctx: any, sessionCookieName: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Strip the OIDC session cookie pair from the INBOUND request header.
|
|
73
|
+
*
|
|
74
|
+
* This is the critical half of the fix. node-oidc-provider is invoked via
|
|
75
|
+
* `provider.callback()(ctx.req, ctx.res)` and reads the session cookie from the
|
|
76
|
+
* raw inbound request (`ctx.req.headers.cookie`) — NOT from anything we write to
|
|
77
|
+
* the response. Clearing the response cookie (via `clearSessionCookies`) only
|
|
78
|
+
* tells the *browser* to drop the cookie on *future* requests; it does nothing
|
|
79
|
+
* for the current request the provider is about to process.
|
|
80
|
+
*
|
|
81
|
+
* To prevent the provider from seeing the stale `_session` during THIS request
|
|
82
|
+
* (and thus hitting the session-id-rotation `SessionNotFound`), we must remove
|
|
83
|
+
* the session cookie pair from `ctx.req.headers.cookie` before calling `next()`.
|
|
84
|
+
*
|
|
85
|
+
* Removes any cookie whose name is exactly `sessionCookieName` or begins with
|
|
86
|
+
* `${sessionCookieName}.` (covers `_session.sig`, `_session.legacy`,
|
|
87
|
+
* `_session.legacy.sig`). All other cookies are preserved unchanged.
|
|
88
|
+
*
|
|
89
|
+
* @param ctx - Koa context (its `ctx.req` is the same raw req the provider reads)
|
|
90
|
+
* @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
|
|
91
|
+
*/
|
|
92
|
+
export declare function stripSessionCookiesFromRequest(ctx: any, sessionCookieName: string): void;
|
|
93
|
+
/**
|
|
94
|
+
* Create the prompt=login session-reset middleware.
|
|
95
|
+
*
|
|
96
|
+
* Mounted in `src/server.ts` BEFORE the `/:orgSlug/*` OIDC router so it runs on
|
|
97
|
+
* the outer Koa context before the provider processes the authorize request.
|
|
98
|
+
*
|
|
99
|
+
* @param provider - OIDC provider instance (used only for the session cookie name)
|
|
100
|
+
* @returns Koa middleware
|
|
101
|
+
*/
|
|
102
|
+
export declare function promptLoginReset(provider: Provider): Middleware;
|
|
103
|
+
//# sourceMappingURL=prompt-login-reset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-login-reset.d.ts","sourceRoot":"","sources":["../../src/middleware/prompt-login-reset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAS1C;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAGzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAEjC,GAAG,EAAE,GAAG,EACR,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAiBN;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,8BAA8B,CAE5C,GAAG,EAAE,GAAG,EACR,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAoBN;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAqD/D"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt=login session-reset middleware.
|
|
3
|
+
*
|
|
4
|
+
* Fixes the "Something went wrong" dead-end on browser re-login (Bug #1).
|
|
5
|
+
*
|
|
6
|
+
* Root cause: a stale `_session` cookie from a previous login survives into a
|
|
7
|
+
* new `prompt=login` authorization flow. The provider rotates the session id
|
|
8
|
+
* during resume, so the interaction's recorded session uid no longer matches
|
|
9
|
+
* the live session uid → node-oidc-provider throws `SessionNotFound` and the
|
|
10
|
+
* user sees a terminal error. (Confirmed: the Redis Session record is present
|
|
11
|
+
* during the failure — this is NOT a Redis durability problem.)
|
|
12
|
+
*
|
|
13
|
+
* Fix: on an initial GET/POST authorize request whose `prompt` parameter
|
|
14
|
+
* contains `login`, clear the `_session` + `_session.sig` cookies BEFORE the
|
|
15
|
+
* provider runs. With no stale cookie, the provider mints a fresh session and
|
|
16
|
+
* there is no uid mismatch. The stale Redis Session record is left to expire on
|
|
17
|
+
* its own via TTL (AR-2, revised) — clearing the cookie is what fixes the bug.
|
|
18
|
+
*
|
|
19
|
+
* Design notes:
|
|
20
|
+
* - Only acts when `prompt` contains the `login` value (AR-3). Normal SSO /
|
|
21
|
+
* session-reuse logins are unaffected (AR-5).
|
|
22
|
+
* - Reads `prompt` from the query string. The CLI and standard browser RP flows
|
|
23
|
+
* use GET authorize with `prompt` in the query, so this covers the real flow
|
|
24
|
+
* without consuming the POST body stream the provider needs (PF-005).
|
|
25
|
+
* - Cookie clearing is signing-free: we expire both `_session` and
|
|
26
|
+
* `_session.sig` explicitly. The outer Koa app does not set `app.keys`, so we
|
|
27
|
+
* must NOT rely on Koa's signed-cookie API here (PF-001/PF-002).
|
|
28
|
+
*
|
|
29
|
+
* @module middleware/prompt-login-reset
|
|
30
|
+
*/
|
|
31
|
+
import { config } from '../config/index.js';
|
|
32
|
+
import { logger } from '../lib/logger.js';
|
|
33
|
+
import { writeAuditLog } from '../lib/audit-log.js';
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Pure helpers (exported for testing)
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Does the OIDC `prompt` parameter request a forced login?
|
|
39
|
+
*
|
|
40
|
+
* Per OIDC Core §3.1.2.1, `prompt` is a space-delimited list of values.
|
|
41
|
+
* Returns true only when `login` is one of those values (exact token match —
|
|
42
|
+
* not a substring, so `logins` or `login_hint` values do not match).
|
|
43
|
+
*
|
|
44
|
+
* @param prompt - The raw `prompt` parameter value (or undefined)
|
|
45
|
+
* @returns true if `login` is present among the space-delimited values
|
|
46
|
+
*/
|
|
47
|
+
export function promptHasLogin(prompt) {
|
|
48
|
+
if (!prompt)
|
|
49
|
+
return false;
|
|
50
|
+
return prompt.split(' ').filter(Boolean).includes('login');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Is this request the INITIAL org-scoped authorize endpoint?
|
|
54
|
+
*
|
|
55
|
+
* Matches `GET`/`POST` `/{orgSlug}/auth` (with optional trailing slash) but
|
|
56
|
+
* NOT the resume route `/{orgSlug}/auth/{uid}` and not other OIDC endpoints
|
|
57
|
+
* (`/token`, `/jwks`, etc.). The resume route must be excluded because the
|
|
58
|
+
* session-mismatch happens there — we reset on the *initial* authorize so the
|
|
59
|
+
* interaction binds to a fresh session.
|
|
60
|
+
*
|
|
61
|
+
* @param method - HTTP method
|
|
62
|
+
* @param path - Request path (outer Koa path, includes the org slug)
|
|
63
|
+
* @returns true if this is the initial authorize endpoint
|
|
64
|
+
*/
|
|
65
|
+
export function isInitialAuthorize(method, path) {
|
|
66
|
+
if (method !== 'GET' && method !== 'POST')
|
|
67
|
+
return false;
|
|
68
|
+
// ^/{slug}/auth or /{slug}/auth/ — exactly one path segment before /auth,
|
|
69
|
+
// and nothing (or only a trailing slash) after.
|
|
70
|
+
return /^\/[^/]+\/auth\/?$/.test(path);
|
|
71
|
+
}
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Cookie clearing (signing-free, shared)
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Clear the OIDC session cookie pair (`_session` + `_session.sig`).
|
|
77
|
+
*
|
|
78
|
+
* Expires BOTH cookie names at path `/` with attributes matching how the
|
|
79
|
+
* provider wrote them (httpOnly, sameSite=lax, secure per issuer scheme). This
|
|
80
|
+
* is intentionally signing-free: it sets each cookie to an expired value
|
|
81
|
+
* directly, so it works regardless of whether `app.keys` is configured on the
|
|
82
|
+
* Koa app (the outer Porta app does not set it). (PF-001/PF-002, AR-2)
|
|
83
|
+
*
|
|
84
|
+
* @param ctx - Koa context (outer app context or provider ctx — both work)
|
|
85
|
+
* @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
|
|
86
|
+
*/
|
|
87
|
+
export function clearSessionCookies(
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
ctx, sessionCookieName) {
|
|
90
|
+
const secure = config.issuerBaseUrl.startsWith('https://');
|
|
91
|
+
const opts = {
|
|
92
|
+
path: '/',
|
|
93
|
+
httpOnly: true,
|
|
94
|
+
sameSite: 'lax',
|
|
95
|
+
secure,
|
|
96
|
+
// Do NOT use signed: true — the outer app has no app.keys.
|
|
97
|
+
signed: false,
|
|
98
|
+
// Expire immediately.
|
|
99
|
+
expires: new Date(0),
|
|
100
|
+
maxAge: 0,
|
|
101
|
+
};
|
|
102
|
+
// Clear the main cookie and its signature companion explicitly.
|
|
103
|
+
ctx.cookies.set(sessionCookieName, null, opts);
|
|
104
|
+
ctx.cookies.set(`${sessionCookieName}.sig`, null, opts);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Strip the OIDC session cookie pair from the INBOUND request header.
|
|
108
|
+
*
|
|
109
|
+
* This is the critical half of the fix. node-oidc-provider is invoked via
|
|
110
|
+
* `provider.callback()(ctx.req, ctx.res)` and reads the session cookie from the
|
|
111
|
+
* raw inbound request (`ctx.req.headers.cookie`) — NOT from anything we write to
|
|
112
|
+
* the response. Clearing the response cookie (via `clearSessionCookies`) only
|
|
113
|
+
* tells the *browser* to drop the cookie on *future* requests; it does nothing
|
|
114
|
+
* for the current request the provider is about to process.
|
|
115
|
+
*
|
|
116
|
+
* To prevent the provider from seeing the stale `_session` during THIS request
|
|
117
|
+
* (and thus hitting the session-id-rotation `SessionNotFound`), we must remove
|
|
118
|
+
* the session cookie pair from `ctx.req.headers.cookie` before calling `next()`.
|
|
119
|
+
*
|
|
120
|
+
* Removes any cookie whose name is exactly `sessionCookieName` or begins with
|
|
121
|
+
* `${sessionCookieName}.` (covers `_session.sig`, `_session.legacy`,
|
|
122
|
+
* `_session.legacy.sig`). All other cookies are preserved unchanged.
|
|
123
|
+
*
|
|
124
|
+
* @param ctx - Koa context (its `ctx.req` is the same raw req the provider reads)
|
|
125
|
+
* @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
|
|
126
|
+
*/
|
|
127
|
+
export function stripSessionCookiesFromRequest(
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
ctx, sessionCookieName) {
|
|
130
|
+
const header = ctx.req?.headers?.cookie;
|
|
131
|
+
if (!header)
|
|
132
|
+
return;
|
|
133
|
+
const prefix = `${sessionCookieName}.`;
|
|
134
|
+
const kept = header
|
|
135
|
+
.split(';')
|
|
136
|
+
.map((pair) => pair.trim())
|
|
137
|
+
.filter((pair) => {
|
|
138
|
+
if (!pair)
|
|
139
|
+
return false;
|
|
140
|
+
const eq = pair.indexOf('=');
|
|
141
|
+
const name = (eq === -1 ? pair : pair.slice(0, eq)).trim();
|
|
142
|
+
return name !== sessionCookieName && !name.startsWith(prefix);
|
|
143
|
+
});
|
|
144
|
+
if (kept.length === 0) {
|
|
145
|
+
delete ctx.req.headers.cookie;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
ctx.req.headers.cookie = kept.join('; ');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Middleware factory
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/**
|
|
155
|
+
* Create the prompt=login session-reset middleware.
|
|
156
|
+
*
|
|
157
|
+
* Mounted in `src/server.ts` BEFORE the `/:orgSlug/*` OIDC router so it runs on
|
|
158
|
+
* the outer Koa context before the provider processes the authorize request.
|
|
159
|
+
*
|
|
160
|
+
* @param provider - OIDC provider instance (used only for the session cookie name)
|
|
161
|
+
* @returns Koa middleware
|
|
162
|
+
*/
|
|
163
|
+
export function promptLoginReset(provider) {
|
|
164
|
+
// Resolve the session cookie name once (e.g. '_session'). `cookieName` is a
|
|
165
|
+
// runtime method on the provider that is not present in the TypeScript types,
|
|
166
|
+
// so we access it via a narrow cast and fall back to the provider default
|
|
167
|
+
// (`_session`) if it is unavailable.
|
|
168
|
+
const providerWithCookieName = provider;
|
|
169
|
+
const sessionCookieName = typeof providerWithCookieName.cookieName === 'function'
|
|
170
|
+
? providerWithCookieName.cookieName('session')
|
|
171
|
+
: '_session';
|
|
172
|
+
return async (ctx, next) => {
|
|
173
|
+
if (!isInitialAuthorize(ctx.method, ctx.path)) {
|
|
174
|
+
return next();
|
|
175
|
+
}
|
|
176
|
+
const prompt = ctx.query.prompt;
|
|
177
|
+
const promptValue = Array.isArray(prompt) ? prompt.join(' ') : prompt;
|
|
178
|
+
if (!promptHasLogin(promptValue)) {
|
|
179
|
+
return next();
|
|
180
|
+
}
|
|
181
|
+
// Force a clean slate. TWO actions are required:
|
|
182
|
+
//
|
|
183
|
+
// 1. Strip the session cookie pair from the INBOUND request header so the
|
|
184
|
+
// provider — invoked this same request via `provider.callback()(ctx.req,
|
|
185
|
+
// ctx.res)`, which reads `ctx.req.headers.cookie` — does NOT see the
|
|
186
|
+
// stale `_session` and cannot hit the session-id-rotation
|
|
187
|
+
// `SessionNotFound`. This is the half that actually fixes the bug.
|
|
188
|
+
// 2. Clear the response cookie pair so the browser drops the stale cookie
|
|
189
|
+
// for future requests too.
|
|
190
|
+
stripSessionCookiesFromRequest(ctx, sessionCookieName);
|
|
191
|
+
clearSessionCookies(ctx, sessionCookieName);
|
|
192
|
+
logger.info({ path: ctx.path }, 'prompt=login: cleared session cookies for forced re-authentication');
|
|
193
|
+
// Best-effort audit (no sensitive data). Fire-and-forget pattern matches
|
|
194
|
+
// writeAuditLog's own contract (it never throws).
|
|
195
|
+
writeAuditLog({
|
|
196
|
+
eventType: 'auth.prompt_login.session_reset',
|
|
197
|
+
eventCategory: 'authentication',
|
|
198
|
+
description: 'Session cookies cleared on prompt=login (forced re-authentication)',
|
|
199
|
+
ipAddress: ctx.ip,
|
|
200
|
+
});
|
|
201
|
+
return next();
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=prompt-login-reset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-login-reset.js","sourceRoot":"","sources":["../../src/middleware/prompt-login-reset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,MAAiC;IAC9D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,IAAY;IAC7D,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACxD,0EAA0E;IAC1E,gDAAgD;IAChD,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,8EAA8E;AAC9E,yCAAyC;AACzC,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB;AACjC,8DAA8D;AAC9D,GAAQ,EACR,iBAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,KAAc;QACxB,MAAM;QACN,2DAA2D;QAC3D,MAAM,EAAE,KAAK;QACb,sBAAsB;QACtB,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC;QACpB,MAAM,EAAE,CAAC;KACV,CAAC;IAEF,gEAAgE;IAChE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,iBAAiB,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,8BAA8B;AAC5C,8DAA8D;AAC9D,GAAQ,EACR,iBAAyB;IAEzB,MAAM,MAAM,GAAuB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;IAC5D,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,MAAM,GAAG,GAAG,iBAAiB,GAAG,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM;SAChB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAClC,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACvB,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,OAAO,IAAI,KAAK,iBAAiB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEL,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB;IACjD,4EAA4E;IAC5E,8EAA8E;IAC9E,0EAA0E;IAC1E,qCAAqC;IACrC,MAAM,sBAAsB,GAAG,QAE9B,CAAC;IACF,MAAM,iBAAiB,GACrB,OAAO,sBAAsB,CAAC,UAAU,KAAK,UAAU;QACrD,CAAC,CAAC,sBAAsB,CAAC,UAAU,CAAC,SAAS,CAAC;QAC9C,CAAC,CAAC,UAAU,CAAC;IAEjB,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAChC,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAEtE,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,iDAAiD;QACjD,EAAE;QACF,0EAA0E;QAC1E,4EAA4E;QAC5E,wEAAwE;QACxE,6DAA6D;QAC7D,sEAAsE;QACtE,0EAA0E;QAC1E,8BAA8B;QAC9B,8BAA8B,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACvD,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAE5C,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAClB,oEAAoE,CACrE,CAAC;QAEF,yEAAyE;QACzE,kDAAkD;QAClD,aAAa,CAAC;YACZ,SAAS,EAAE,iCAAiC;YAC5C,aAAa,EAAE,gBAAgB;YAC/B,WAAW,EAAE,oEAAoE;YACjF,SAAS,EAAE,GAAG,CAAC,EAAE;SAClB,CAAC,CAAC;QAEH,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Readiness probe handler — GET /ready.
|
|
3
|
+
*
|
|
4
|
+
* Separate from /health (liveness): /health confirms the server process
|
|
5
|
+
* is alive; /ready confirms the server can actually serve requests by
|
|
6
|
+
* checking that both PostgreSQL and Redis are reachable within a timeout.
|
|
7
|
+
*
|
|
8
|
+
* Kubernetes / ECS maps:
|
|
9
|
+
* - livenessProbe → GET /health
|
|
10
|
+
* - readinessProbe → GET /ready
|
|
11
|
+
*
|
|
12
|
+
* Returns 200 + { status: 'ready', checks } when both backends are healthy,
|
|
13
|
+
* or 503 + { status: 'not_ready', checks } when either is degraded.
|
|
14
|
+
*/
|
|
15
|
+
import type { Middleware } from 'koa';
|
|
16
|
+
/**
|
|
17
|
+
* Create the readiness probe middleware.
|
|
18
|
+
*
|
|
19
|
+
* Both DB and Redis are checked concurrently with individual timeouts.
|
|
20
|
+
* A single failure makes the overall probe return 503.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readyHandler(): Middleware;
|
|
23
|
+
//# sourceMappingURL=ready.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAwBtC;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,UAAU,CA6BzC"}
|