@lastshotlabs/bunshot 0.0.27 → 0.0.28
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/.oclif.manifest.json +39 -0
- package/README.md +8282 -2147
- package/dist/cli/commands/init.js +690 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli.js +4 -4
- package/dist/packages/bunshot-admin/src/index.d.ts +15 -0
- package/dist/packages/bunshot-admin/src/index.js +11 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.js +33 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.js +17 -0
- package/dist/packages/bunshot-admin/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-admin/src/plugin.js +46 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.js +32 -0
- package/dist/packages/bunshot-admin/src/routes/admin.d.ts +10 -0
- package/dist/packages/bunshot-admin/src/routes/admin.js +923 -0
- package/dist/packages/bunshot-admin/src/routes/mail.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/routes/mail.js +114 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.js +315 -0
- package/dist/packages/bunshot-admin/src/types/config.d.ts +16 -0
- package/dist/packages/bunshot-admin/src/types/config.js +37 -0
- package/dist/packages/bunshot-admin/src/types/env.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/types/provider.d.ts +1 -0
- package/dist/packages/bunshot-admin/src/types/provider.js +4 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.js +1063 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.js +536 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.d.ts +88 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.js +1366 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.js +23 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.js +131 -0
- package/dist/packages/bunshot-auth/src/bootstrap.d.ts +38 -0
- package/dist/packages/bunshot-auth/src/bootstrap.js +384 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.js +4 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.d.ts +478 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.js +46 -0
- package/dist/packages/bunshot-auth/src/config/configLock.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/config/configLock.js +10 -0
- package/dist/packages/bunshot-auth/src/index.d.ts +25 -0
- package/dist/packages/bunshot-auth/src/index.js +23 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.js +44 -0
- package/dist/packages/bunshot-auth/src/infra/queue.d.ts +14 -0
- package/dist/packages/bunshot-auth/src/infra/queue.js +27 -0
- package/dist/packages/bunshot-auth/src/infra/redis.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/infra/redis.js +15 -0
- package/dist/packages/bunshot-auth/src/infra/signing.d.ts +7 -0
- package/dist/packages/bunshot-auth/src/infra/signing.js +8 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.d.ts +34 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.js +244 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.js +15 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.js +205 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.d.ts +8 -2
- package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.js +22 -9
- package/dist/packages/bunshot-auth/src/lib/cache.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/cache.js +120 -0
- package/dist/packages/bunshot-auth/src/lib/clientIp.d.ts +4 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/clientIp.js +14 -7
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.d.ts +27 -0
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.js +33 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.d.ts +40 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.js +221 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.d.ts +23 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.js +265 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.d.ts +30 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.js +200 -0
- package/dist/packages/bunshot-auth/src/lib/env.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/env.js +3 -0
- package/dist/packages/bunshot-auth/src/lib/fingerprint.js +36 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.d.ts +15 -16
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.js +22 -34
- package/dist/packages/bunshot-auth/src/lib/jwks.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/jwks.js +79 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.js +86 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/logger.js +3 -3
- package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.d.ts +5 -4
- package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.js +6 -10
- package/dist/packages/bunshot-auth/src/lib/magicLink.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/magicLink.js +145 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.d.ts +60 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.js +419 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.d.ts +82 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.js +177 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.js +182 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.js +255 -0
- package/dist/packages/bunshot-auth/src/lib/organization.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/lib/organization.js +225 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.js +31 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.d.ts +20 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/roles.d.ts +9 -0
- package/dist/packages/bunshot-auth/src/lib/roles.js +93 -0
- package/dist/packages/bunshot-auth/src/lib/saml.d.ts +29 -0
- package/dist/packages/bunshot-auth/src/lib/saml.js +73 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.js +129 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/scim.d.ts +7 -7
- package/dist/{lib → packages/bunshot-auth/src/lib}/scim.js +15 -13
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.d.ts +22 -0
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.js +65 -0
- package/dist/packages/bunshot-auth/src/lib/session.d.ts +45 -0
- package/dist/packages/bunshot-auth/src/lib/session.js +1211 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.d.ts +26 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.js +18 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.d.ts +3 -2
- package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.js +2 -5
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.d.ts +16 -0
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.js +161 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.js +58 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/csrf.d.ts +5 -4
- package/dist/packages/bunshot-auth/src/middleware/csrf.js +138 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.js +124 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.js +10 -8
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.js +20 -16
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.js +6 -6
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.js +8 -7
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.js +7 -6
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.d.ts +8 -0
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.js +29 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.js +6 -0
- package/dist/{models → packages/bunshot-auth/src/models}/AuthUser.d.ts +12 -8
- package/dist/packages/bunshot-auth/src/models/AuthUser.js +53 -0
- package/dist/packages/bunshot-auth/src/models/Group.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/models/Group.js +22 -0
- package/dist/{models → packages/bunshot-auth/src/models}/GroupMembership.d.ts +6 -8
- package/dist/packages/bunshot-auth/src/models/GroupMembership.js +19 -0
- package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.d.ts +1 -1
- package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.js +5 -5
- package/dist/packages/bunshot-auth/src/models/TenantRole.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/models/TenantRole.js +17 -0
- package/dist/packages/bunshot-auth/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/plugin.js +274 -0
- package/dist/packages/bunshot-auth/src/routes/auth.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/routes/auth.js +1624 -0
- package/dist/packages/bunshot-auth/src/routes/groups.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/routes/groups.js +481 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.js +145 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.js +991 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.js +1727 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.js +84 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.js +741 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.js +199 -0
- package/dist/packages/bunshot-auth/src/routes/saml.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/saml.js +226 -0
- package/dist/packages/bunshot-auth/src/routes/scim.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/scim.js +588 -0
- package/dist/packages/bunshot-auth/src/runtime.d.ts +52 -0
- package/dist/packages/bunshot-auth/src/runtime.js +11 -0
- package/dist/{schemas → packages/bunshot-auth/src/schemas}/auth.d.ts +4 -5
- package/dist/packages/bunshot-auth/src/schemas/auth.js +24 -0
- package/dist/packages/bunshot-auth/src/schemas/error.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/error.js +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.js +10 -0
- package/dist/packages/bunshot-auth/src/services/auth.d.ts +39 -0
- package/dist/packages/bunshot-auth/src/services/auth.js +378 -0
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.d.ts +41 -17
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.js +259 -183
- package/dist/packages/bunshot-auth/src/testing.d.ts +31 -0
- package/dist/packages/bunshot-auth/src/testing.js +23 -0
- package/dist/packages/bunshot-auth/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-auth/src/types/config.d.ts +152 -0
- package/dist/packages/bunshot-auth/src/types/config.js +179 -0
- package/dist/{routes → packages/bunshot-auth/src/types}/groups.d.ts +2 -3
- package/dist/packages/bunshot-auth/src/types/groups.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.js +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.js +1 -0
- package/dist/packages/bunshot-auth/src/types/saml.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/types/saml.js +1 -0
- package/dist/packages/bunshot-auth/src/types/session.d.ts +18 -0
- package/dist/packages/bunshot-auth/src/types/session.js +1 -0
- package/dist/packages/bunshot-auth/src/types/store.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/store.js +1 -0
- package/dist/packages/bunshot-core/src/adminProvider.d.ts +95 -0
- package/dist/packages/bunshot-core/src/adminProvider.js +1 -0
- package/dist/packages/bunshot-core/src/auditLog.d.ts +34 -0
- package/dist/packages/bunshot-core/src/auditLog.js +1 -0
- package/dist/packages/bunshot-core/src/auth-adapter.d.ts +227 -0
- package/dist/packages/bunshot-core/src/auth-adapter.js +4 -0
- package/dist/packages/bunshot-core/src/authVariables.d.ts +14 -0
- package/dist/packages/bunshot-core/src/authVariables.js +4 -0
- package/dist/packages/bunshot-core/src/cache.d.ts +12 -0
- package/dist/packages/bunshot-core/src/cache.js +21 -0
- package/dist/{lib → packages/bunshot-core/src}/captcha.d.ts +1 -10
- package/dist/packages/bunshot-core/src/captcha.js +1 -0
- package/dist/packages/bunshot-core/src/clearRegistry.d.ts +6 -0
- package/dist/packages/bunshot-core/src/clearRegistry.js +17 -0
- package/dist/packages/bunshot-core/src/clientIp.d.ts +3 -0
- package/dist/packages/bunshot-core/src/clientIp.js +45 -0
- package/dist/packages/bunshot-core/src/configLock.d.ts +4 -0
- package/dist/packages/bunshot-core/src/configLock.js +7 -0
- package/dist/packages/bunshot-core/src/configValidation.d.ts +22 -0
- package/dist/packages/bunshot-core/src/configValidation.js +39 -0
- package/dist/packages/bunshot-core/src/constants.js +10 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.d.ts +232 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.js +1 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.d.ts +3 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.js +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.d.ts +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.js +31 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.d.ts +38 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.js +1 -0
- package/dist/packages/bunshot-core/src/context/index.d.ts +4 -0
- package/dist/packages/bunshot-core/src/context/index.js +2 -0
- package/dist/packages/bunshot-core/src/context.d.ts +40 -0
- package/dist/packages/bunshot-core/src/context.js +35 -0
- package/dist/packages/bunshot-core/src/coreContracts.d.ts +47 -0
- package/dist/packages/bunshot-core/src/coreContracts.js +1 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.d.ts +6 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.js +42 -0
- package/dist/{lib → packages/bunshot-core/src}/createRoute.d.ts +4 -30
- package/dist/{lib → packages/bunshot-core/src}/createRoute.js +39 -88
- package/dist/packages/bunshot-core/src/cronRegistry.d.ts +11 -0
- package/dist/packages/bunshot-core/src/cronRegistry.js +1 -0
- package/dist/packages/bunshot-core/src/crypto.d.ts +43 -0
- package/dist/packages/bunshot-core/src/crypto.js +74 -0
- package/dist/packages/bunshot-core/src/csrf.d.ts +8 -0
- package/dist/packages/bunshot-core/src/csrf.js +1 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.d.ts +7 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.js +19 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.js +40 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.js +24 -0
- package/dist/packages/bunshot-core/src/emailTemplates.d.ts +5 -0
- package/dist/packages/bunshot-core/src/emailTemplates.js +10 -0
- package/dist/{lib/HttpError.d.ts → packages/bunshot-core/src/errors.d.ts} +4 -1
- package/dist/{lib/HttpError.js → packages/bunshot-core/src/errors.js} +7 -1
- package/dist/packages/bunshot-core/src/eventBus.d.ts +270 -0
- package/dist/packages/bunshot-core/src/eventBus.js +143 -0
- package/dist/packages/bunshot-core/src/idempotency.d.ts +18 -0
- package/dist/packages/bunshot-core/src/idempotency.js +1 -0
- package/dist/packages/bunshot-core/src/index.d.ts +60 -0
- package/dist/packages/bunshot-core/src/index.js +34 -0
- package/dist/packages/bunshot-core/src/mail.d.ts +14 -0
- package/dist/packages/bunshot-core/src/mail.js +8 -0
- package/dist/packages/bunshot-core/src/memoryEviction.d.ts +24 -0
- package/dist/packages/bunshot-core/src/memoryEviction.js +52 -0
- package/dist/packages/bunshot-core/src/pagination.d.ts +45 -0
- package/dist/packages/bunshot-core/src/pagination.js +61 -0
- package/dist/packages/bunshot-core/src/permissions.d.ts +64 -0
- package/dist/packages/bunshot-core/src/permissions.js +27 -0
- package/dist/packages/bunshot-core/src/plugin.d.ts +44 -0
- package/dist/packages/bunshot-core/src/plugin.js +1 -0
- package/dist/packages/bunshot-core/src/rateLimit.d.ts +5 -0
- package/dist/packages/bunshot-core/src/rateLimit.js +18 -0
- package/dist/packages/bunshot-core/src/redis.d.ts +21 -0
- package/dist/packages/bunshot-core/src/redis.js +1 -0
- package/dist/packages/bunshot-core/src/routeAuth.d.ts +5 -0
- package/dist/packages/bunshot-core/src/routeAuth.js +11 -0
- package/dist/packages/bunshot-core/src/routeOverrides.d.ts +24 -0
- package/dist/packages/bunshot-core/src/routeOverrides.js +25 -0
- package/dist/packages/bunshot-core/src/routerAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/routerAdapter.js +56 -0
- package/dist/packages/bunshot-core/src/secrets.d.ts +48 -0
- package/dist/packages/bunshot-core/src/secrets.js +8 -0
- package/dist/packages/bunshot-core/src/signing.d.ts +41 -0
- package/dist/packages/bunshot-core/src/signing.js +1 -0
- package/dist/packages/bunshot-core/src/sse.d.ts +36 -0
- package/dist/packages/bunshot-core/src/sse.js +1 -0
- package/dist/packages/bunshot-core/src/storageAdapter.js +1 -0
- package/dist/packages/bunshot-core/src/storeInfra.d.ts +44 -0
- package/dist/packages/bunshot-core/src/storeInfra.js +18 -0
- package/dist/packages/bunshot-core/src/storeType.d.ts +7 -0
- package/dist/packages/bunshot-core/src/storeType.js +1 -0
- package/dist/packages/bunshot-core/src/testing.d.ts +1 -0
- package/dist/packages/bunshot-core/src/testing.js +1 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.d.ts +23 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.js +4 -0
- package/dist/packages/bunshot-core/src/userResolver.d.ts +5 -0
- package/dist/packages/bunshot-core/src/userResolver.js +14 -0
- package/dist/packages/bunshot-core/src/wsMessages.d.ts +42 -0
- package/dist/packages/bunshot-core/src/wsMessages.js +4 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.js +73 -0
- package/dist/packages/bunshot-permissions/src/index.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/index.js +5 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.js +12 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.js +165 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.d.ts +2 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.js +31 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.js +1 -0
- package/dist/packages/bunshot-postgres/src/adapter.d.ts +6 -0
- package/dist/packages/bunshot-postgres/src/adapter.js +794 -0
- package/dist/packages/bunshot-postgres/src/connection.d.ts +15 -0
- package/dist/packages/bunshot-postgres/src/connection.js +16 -0
- package/dist/packages/bunshot-postgres/src/index.d.ts +4 -0
- package/dist/packages/bunshot-postgres/src/index.js +2 -0
- package/dist/packages/bunshot-postgres/src/schema.d.ts +997 -0
- package/dist/packages/bunshot-postgres/src/schema.js +105 -0
- package/dist/src/app.d.ts +230 -0
- package/dist/src/app.js +182 -0
- package/dist/src/cli/commands/init.d.ts +10 -0
- package/dist/src/cli/commands/init.js +709 -0
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +3 -0
- package/dist/src/entrypoints/mongo.d.ts +6 -0
- package/dist/src/entrypoints/mongo.js +4 -0
- package/dist/src/entrypoints/queue.d.ts +2 -0
- package/dist/src/entrypoints/queue.js +1 -0
- package/dist/src/entrypoints/redis.d.ts +1 -0
- package/dist/src/entrypoints/redis.js +1 -0
- package/dist/{adapters → src/framework/adapters}/localStorage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/localStorage.js +10 -10
- package/dist/src/framework/adapters/memoryStorage.d.ts +2 -0
- package/dist/src/framework/adapters/memoryStorage.js +45 -0
- package/dist/{adapters → src/framework/adapters}/s3Storage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/s3Storage.js +12 -12
- package/dist/src/framework/admin/bunshotAccess.d.ts +2 -0
- package/dist/src/framework/admin/bunshotAccess.js +23 -0
- package/dist/src/framework/admin/bunshotUsers.d.ts +2 -0
- package/dist/src/framework/admin/bunshotUsers.js +103 -0
- package/dist/src/framework/admin/index.d.ts +7 -0
- package/dist/src/framework/admin/index.js +21 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.d.ts +13 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.js +86 -0
- package/dist/src/framework/boundaryAdapters/index.d.ts +2 -0
- package/dist/src/framework/boundaryAdapters/index.js +1 -0
- package/dist/src/framework/boundaryAdapters.d.ts +17 -0
- package/dist/src/framework/boundaryAdapters.js +62 -0
- package/dist/src/framework/buildContext.d.ts +33 -0
- package/dist/src/framework/buildContext.js +119 -0
- package/dist/src/framework/config/schema.d.ts +447 -0
- package/dist/src/framework/config/schema.js +528 -0
- package/dist/src/framework/createInfrastructure.d.ts +76 -0
- package/dist/src/framework/createInfrastructure.js +221 -0
- package/dist/src/framework/lib/auditLog.d.ts +23 -0
- package/dist/src/framework/lib/auditLog.js +416 -0
- package/dist/src/framework/lib/captcha.d.ts +11 -0
- package/dist/{lib → src/framework/lib}/captcha.js +13 -10
- package/dist/{lib → src/framework/lib}/createDtoMapper.js +4 -4
- package/dist/src/framework/lib/createRoute.d.ts +1 -0
- package/dist/src/framework/lib/createRoute.js +2 -0
- package/dist/{lib → src/framework/lib}/idempotency.d.ts +2 -6
- package/dist/src/framework/lib/idempotency.js +74 -0
- package/dist/src/framework/lib/logger.d.ts +3 -0
- package/dist/src/framework/lib/logger.js +14 -0
- package/dist/src/framework/lib/metrics.d.ts +34 -0
- package/dist/{lib → src/framework/lib}/metrics.js +49 -57
- package/dist/src/framework/lib/pagination.d.ts +42 -0
- package/dist/src/framework/lib/pagination.js +51 -0
- package/dist/src/framework/lib/redisTransport.d.ts +38 -0
- package/dist/src/framework/lib/redisTransport.js +107 -0
- package/dist/src/framework/lib/resolveUserId.d.ts +2 -0
- package/dist/src/framework/lib/resolveUserId.js +5 -0
- package/dist/src/framework/lib/sseCollision.d.ts +6 -0
- package/dist/src/framework/lib/sseCollision.js +26 -0
- package/dist/src/framework/lib/storageAdapter.d.ts +1 -0
- package/dist/src/framework/lib/storageAdapter.js +1 -0
- package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.js +4 -4
- package/dist/src/framework/lib/tenant.d.ts +21 -0
- package/dist/src/framework/lib/tenant.js +70 -0
- package/dist/{lib → src/framework/lib}/upload.d.ts +11 -10
- package/dist/src/framework/lib/upload.js +132 -0
- package/dist/src/framework/lib/uploadRegistry.d.ts +23 -0
- package/dist/src/framework/lib/uploadRegistry.js +34 -0
- package/dist/{lib → src/framework/lib}/validate.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/validate.js +2 -2
- package/dist/src/framework/lib/ws.d.ts +19 -0
- package/dist/src/framework/lib/ws.js +130 -0
- package/dist/src/framework/lib/wsHeartbeat.d.ts +12 -0
- package/dist/src/framework/lib/wsHeartbeat.js +53 -0
- package/dist/src/framework/lib/wsMessages.d.ts +25 -0
- package/dist/src/framework/lib/wsMessages.js +45 -0
- package/dist/src/framework/lib/wsNamespace.d.ts +17 -0
- package/dist/src/framework/lib/wsNamespace.js +19 -0
- package/dist/src/framework/lib/wsPresence.d.ts +17 -0
- package/dist/src/framework/lib/wsPresence.js +84 -0
- package/dist/src/framework/lib/wsTransport.d.ts +38 -0
- package/dist/src/framework/lib/wsTransport.js +9 -0
- package/dist/{lib → src/framework/lib}/zodToMongoose.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/zodToMongoose.js +11 -11
- package/dist/{middleware → src/framework/middleware}/auditLog.d.ts +4 -3
- package/dist/src/framework/middleware/auditLog.js +42 -0
- package/dist/{middleware → src/framework/middleware}/botProtection.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/botProtection.js +8 -9
- package/dist/src/framework/middleware/cacheResponse.d.ts +35 -0
- package/dist/src/framework/middleware/cacheResponse.js +126 -0
- package/dist/{middleware → src/framework/middleware}/captcha.d.ts +2 -3
- package/dist/src/framework/middleware/captcha.js +37 -0
- package/dist/{middleware → src/framework/middleware}/errorHandler.d.ts +1 -1
- package/dist/{middleware → src/framework/middleware}/errorHandler.js +2 -2
- package/dist/src/framework/middleware/index.js +1 -0
- package/dist/{middleware → src/framework/middleware}/logger.d.ts +1 -1
- package/dist/src/framework/middleware/metrics.d.ts +12 -0
- package/dist/src/framework/middleware/metrics.js +26 -0
- package/dist/{middleware → src/framework/middleware}/rateLimit.d.ts +2 -2
- package/dist/src/framework/middleware/rateLimit.js +22 -0
- package/dist/src/framework/middleware/requestId.d.ts +3 -0
- package/dist/{middleware → src/framework/middleware}/requestId.js +2 -2
- package/dist/{middleware → src/framework/middleware}/requestLogger.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/requestLogger.js +17 -12
- package/dist/{middleware → src/framework/middleware}/requestSigning.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/requestSigning.js +18 -20
- package/dist/src/framework/middleware/tenant.d.ts +14 -0
- package/dist/{middleware → src/framework/middleware}/tenant.js +31 -27
- package/dist/src/framework/middleware/upload.d.ts +5 -0
- package/dist/{middleware → src/framework/middleware}/upload.js +4 -4
- package/dist/{middleware → src/framework/middleware}/webhookAuth.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/webhookAuth.js +11 -12
- package/dist/src/framework/models/AuditLog.d.ts +21 -0
- package/dist/src/framework/models/AuditLog.js +31 -0
- package/dist/src/framework/mountMiddleware.d.ts +91 -0
- package/dist/src/framework/mountMiddleware.js +128 -0
- package/dist/src/framework/mountOptionalEndpoints.d.ts +103 -0
- package/dist/src/framework/mountOptionalEndpoints.js +47 -0
- package/dist/src/framework/mountRoutes.d.ts +21 -0
- package/dist/src/framework/mountRoutes.js +144 -0
- package/dist/src/framework/persistence/cronRegistry.d.ts +28 -0
- package/dist/src/framework/persistence/cronRegistry.js +139 -0
- package/dist/src/framework/persistence/idempotency.d.ts +26 -0
- package/dist/src/framework/persistence/idempotency.js +178 -0
- package/dist/src/framework/persistence/index.d.ts +6 -0
- package/dist/src/framework/persistence/index.js +8 -0
- package/dist/src/framework/persistence/storeInfra.d.ts +9 -0
- package/dist/src/framework/persistence/storeInfra.js +1 -0
- package/dist/src/framework/persistence/uploadRegistry.d.ts +35 -0
- package/dist/src/framework/persistence/uploadRegistry.js +235 -0
- package/dist/src/framework/persistence/wsMessages.d.ts +22 -0
- package/dist/src/framework/persistence/wsMessages.js +296 -0
- package/dist/src/framework/preloadSchemas.d.ts +24 -0
- package/dist/src/framework/preloadSchemas.js +42 -0
- package/dist/src/framework/registerBoundaryAdapters.d.ts +23 -0
- package/dist/src/framework/registerBoundaryAdapters.js +46 -0
- package/dist/src/framework/routes/admin.d.ts +9 -0
- package/dist/src/framework/routes/admin.js +361 -0
- package/dist/src/framework/routes/health.d.ts +1 -0
- package/dist/src/framework/routes/health.js +21 -0
- package/dist/src/framework/routes/home.d.ts +1 -0
- package/dist/src/framework/routes/home.js +18 -0
- package/dist/src/framework/routes/jobs.d.ts +3 -0
- package/dist/{routes → src/framework/routes}/jobs.js +128 -103
- package/dist/src/framework/routes/metrics.d.ts +10 -0
- package/dist/src/framework/routes/metrics.js +57 -0
- package/dist/{routes → src/framework/routes}/uploads.d.ts +3 -3
- package/dist/src/framework/routes/uploads.js +262 -0
- package/dist/src/framework/runPluginLifecycle.d.ts +27 -0
- package/dist/src/framework/runPluginLifecycle.js +121 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.d.ts +58 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.js +20 -0
- package/dist/src/framework/secrets/index.d.ts +9 -0
- package/dist/src/framework/secrets/index.js +7 -0
- package/dist/src/framework/secrets/providers/envProvider.d.ts +15 -0
- package/dist/src/framework/secrets/providers/envProvider.js +18 -0
- package/dist/src/framework/secrets/providers/fileProvider.d.ts +8 -0
- package/dist/src/framework/secrets/providers/fileProvider.js +82 -0
- package/dist/src/framework/secrets/providers/ssmProvider.d.ts +20 -0
- package/dist/src/framework/secrets/providers/ssmProvider.js +127 -0
- package/dist/src/framework/secrets/resolveSecretBundle.d.ts +53 -0
- package/dist/src/framework/secrets/resolveSecretBundle.js +84 -0
- package/dist/src/framework/secrets/resolveSecrets.d.ts +18 -0
- package/dist/src/framework/secrets/resolveSecrets.js +34 -0
- package/dist/src/framework/sse/index.d.ts +21 -0
- package/dist/src/framework/sse/index.js +109 -0
- package/dist/src/framework/ws/index.d.ts +11 -0
- package/dist/src/framework/ws/index.js +8 -0
- package/dist/src/index.d.ts +87 -0
- package/dist/src/index.js +58 -0
- package/dist/src/lib/appConfig.d.ts +7 -0
- package/dist/src/lib/appConfig.js +27 -0
- package/dist/src/lib/appMeta.d.ts +7 -0
- package/dist/src/lib/appMeta.js +3 -0
- package/dist/src/lib/authConfig.d.ts +532 -0
- package/dist/{lib/appConfig.js → src/lib/authConfig.js} +75 -17
- package/dist/{lib → src/lib}/context.d.ts +6 -12
- package/dist/{lib → src/lib}/context.js +5 -5
- package/dist/src/lib/logger.d.ts +1 -0
- package/dist/src/lib/logger.js +1 -0
- package/dist/src/lib/mongo.d.ts +58 -0
- package/dist/src/lib/mongo.js +96 -0
- package/dist/src/lib/queue.d.ts +72 -0
- package/dist/src/lib/queue.js +152 -0
- package/dist/src/lib/redis.d.ts +28 -0
- package/dist/src/lib/redis.js +72 -0
- package/dist/{lib → src/lib}/signing.d.ts +2 -2
- package/dist/src/lib/signing.js +210 -0
- package/dist/src/lib/signingConfig.d.ts +40 -0
- package/dist/src/lib/signingConfig.js +28 -0
- package/dist/src/server.d.ts +146 -0
- package/dist/src/server.js +469 -0
- package/dist/src/shared/lib/HttpError.d.ts +1 -0
- package/dist/src/shared/lib/HttpError.js +2 -0
- package/dist/src/shared/lib/constants.d.ts +10 -0
- package/dist/src/shared/lib/crypto.d.ts +43 -0
- package/dist/src/shared/lib/crypto.js +74 -0
- package/dist/src/shared/lib/signing.d.ts +52 -0
- package/dist/{lib → src/shared/lib}/signing.js +35 -8
- package/dist/src/testing.d.ts +34 -0
- package/dist/src/testing.js +93 -0
- package/package.json +60 -24
- package/dist/adapters/memoryAuth.d.ts +0 -52
- package/dist/adapters/memoryAuth.js +0 -749
- package/dist/adapters/memoryStorage.d.ts +0 -3
- package/dist/adapters/memoryStorage.js +0 -44
- package/dist/adapters/mongoAuth.d.ts +0 -2
- package/dist/adapters/mongoAuth.js +0 -403
- package/dist/adapters/sqliteAuth.d.ts +0 -72
- package/dist/adapters/sqliteAuth.js +0 -858
- package/dist/app.d.ts +0 -559
- package/dist/app.js +0 -651
- package/dist/entrypoints/mongo.d.ts +0 -5
- package/dist/entrypoints/mongo.js +0 -4
- package/dist/entrypoints/queue.d.ts +0 -2
- package/dist/entrypoints/queue.js +0 -1
- package/dist/entrypoints/redis.d.ts +0 -1
- package/dist/entrypoints/redis.js +0 -1
- package/dist/index.d.ts +0 -117
- package/dist/index.js +0 -88
- package/dist/lib/appConfig.d.ts +0 -275
- package/dist/lib/auditLog.d.ts +0 -58
- package/dist/lib/auditLog.js +0 -218
- package/dist/lib/authAdapter.d.ts +0 -246
- package/dist/lib/authAdapter.js +0 -7
- package/dist/lib/authRateLimit.d.ts +0 -13
- package/dist/lib/authRateLimit.js +0 -117
- package/dist/lib/clientIp.d.ts +0 -14
- package/dist/lib/credentialStuffing.d.ts +0 -31
- package/dist/lib/credentialStuffing.js +0 -77
- package/dist/lib/crypto.d.ts +0 -11
- package/dist/lib/crypto.js +0 -22
- package/dist/lib/deletionCancelToken.d.ts +0 -12
- package/dist/lib/deletionCancelToken.js +0 -88
- package/dist/lib/emailVerification.d.ts +0 -19
- package/dist/lib/emailVerification.js +0 -129
- package/dist/lib/fingerprint.js +0 -36
- package/dist/lib/idempotency.js +0 -182
- package/dist/lib/jwks.d.ts +0 -25
- package/dist/lib/jwks.js +0 -51
- package/dist/lib/jwt.d.ts +0 -15
- package/dist/lib/jwt.js +0 -111
- package/dist/lib/metrics.d.ts +0 -14
- package/dist/lib/mfaChallenge.d.ts +0 -55
- package/dist/lib/mfaChallenge.js +0 -398
- package/dist/lib/mongo.d.ts +0 -39
- package/dist/lib/mongo.js +0 -124
- package/dist/lib/oauth.d.ts +0 -40
- package/dist/lib/oauth.js +0 -101
- package/dist/lib/oauthCode.d.ts +0 -15
- package/dist/lib/oauthCode.js +0 -95
- package/dist/lib/pagination.d.ts +0 -119
- package/dist/lib/pagination.js +0 -166
- package/dist/lib/queue.d.ts +0 -37
- package/dist/lib/queue.js +0 -117
- package/dist/lib/redis.d.ts +0 -9
- package/dist/lib/redis.js +0 -61
- package/dist/lib/resetPassword.d.ts +0 -12
- package/dist/lib/resetPassword.js +0 -93
- package/dist/lib/roles.d.ts +0 -7
- package/dist/lib/roles.js +0 -49
- package/dist/lib/saml.d.ts +0 -25
- package/dist/lib/saml.js +0 -64
- package/dist/lib/securityEvents.d.ts +0 -28
- package/dist/lib/securityEvents.js +0 -26
- package/dist/lib/session.d.ts +0 -49
- package/dist/lib/session.js +0 -597
- package/dist/lib/tenant.d.ts +0 -15
- package/dist/lib/tenant.js +0 -65
- package/dist/lib/upload.js +0 -112
- package/dist/lib/uploadRegistry.d.ts +0 -18
- package/dist/lib/uploadRegistry.js +0 -83
- package/dist/lib/ws.d.ts +0 -22
- package/dist/lib/ws.js +0 -96
- package/dist/lib/wsHeartbeat.d.ts +0 -12
- package/dist/lib/wsHeartbeat.js +0 -57
- package/dist/lib/wsMessages.d.ts +0 -40
- package/dist/lib/wsMessages.js +0 -330
- package/dist/lib/wsPresence.d.ts +0 -25
- package/dist/lib/wsPresence.js +0 -99
- package/dist/middleware/auditLog.js +0 -39
- package/dist/middleware/bearerAuth.d.ts +0 -2
- package/dist/middleware/bearerAuth.js +0 -11
- package/dist/middleware/cacheResponse.d.ts +0 -15
- package/dist/middleware/cacheResponse.js +0 -178
- package/dist/middleware/captcha.js +0 -36
- package/dist/middleware/csrf.js +0 -129
- package/dist/middleware/identify.d.ts +0 -3
- package/dist/middleware/identify.js +0 -122
- package/dist/middleware/index.js +0 -1
- package/dist/middleware/metrics.d.ts +0 -9
- package/dist/middleware/metrics.js +0 -26
- package/dist/middleware/rateLimit.js +0 -22
- package/dist/middleware/requestId.d.ts +0 -3
- package/dist/middleware/scimAuth.d.ts +0 -8
- package/dist/middleware/scimAuth.js +0 -29
- package/dist/middleware/tenant.d.ts +0 -5
- package/dist/middleware/upload.d.ts +0 -5
- package/dist/middleware/userAuth.d.ts +0 -3
- package/dist/middleware/userAuth.js +0 -6
- package/dist/models/AuditLog.d.ts +0 -30
- package/dist/models/AuditLog.js +0 -39
- package/dist/models/AuthUser.js +0 -55
- package/dist/models/Group.d.ts +0 -21
- package/dist/models/Group.js +0 -28
- package/dist/models/GroupMembership.js +0 -25
- package/dist/models/TenantRole.d.ts +0 -15
- package/dist/models/TenantRole.js +0 -23
- package/dist/routes/auth.d.ts +0 -12
- package/dist/routes/auth.js +0 -744
- package/dist/routes/groups.js +0 -346
- package/dist/routes/health.d.ts +0 -1
- package/dist/routes/health.js +0 -22
- package/dist/routes/home.d.ts +0 -1
- package/dist/routes/home.js +0 -16
- package/dist/routes/jobs.d.ts +0 -2
- package/dist/routes/m2m.d.ts +0 -2
- package/dist/routes/m2m.js +0 -72
- package/dist/routes/metrics.d.ts +0 -8
- package/dist/routes/metrics.js +0 -55
- package/dist/routes/mfa.d.ts +0 -5
- package/dist/routes/mfa.js +0 -628
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/oauth.js +0 -520
- package/dist/routes/oidc.d.ts +0 -2
- package/dist/routes/oidc.js +0 -29
- package/dist/routes/passkey.d.ts +0 -1
- package/dist/routes/passkey.js +0 -157
- package/dist/routes/saml.d.ts +0 -2
- package/dist/routes/saml.js +0 -86
- package/dist/routes/scim.d.ts +0 -2
- package/dist/routes/scim.js +0 -255
- package/dist/routes/uploads.js +0 -227
- package/dist/schemas/auth.js +0 -30
- package/dist/server.d.ts +0 -57
- package/dist/server.js +0 -112
- package/dist/services/auth.d.ts +0 -29
- package/dist/services/auth.js +0 -238
- package/dist/ws/index.d.ts +0 -10
- package/dist/ws/index.js +0 -39
- package/docs/sections/adding-middleware/full.md +0 -35
- package/docs/sections/adding-models/full.md +0 -125
- package/docs/sections/adding-models/overview.md +0 -13
- package/docs/sections/adding-routes/full.md +0 -182
- package/docs/sections/adding-routes/overview.md +0 -23
- package/docs/sections/auth-flow/full.md +0 -790
- package/docs/sections/auth-flow/overview.md +0 -10
- package/docs/sections/auth-security-examples/full.md +0 -388
- package/docs/sections/authentication/full.md +0 -130
- package/docs/sections/authentication/overview.md +0 -5
- package/docs/sections/cli/full.md +0 -42
- package/docs/sections/configuration/full.md +0 -172
- package/docs/sections/configuration/overview.md +0 -18
- package/docs/sections/configuration-example/full.md +0 -117
- package/docs/sections/configuration-example/overview.md +0 -30
- package/docs/sections/documentation/full.md +0 -171
- package/docs/sections/environment-variables/full.md +0 -55
- package/docs/sections/exports/full.md +0 -123
- package/docs/sections/extending-context/full.md +0 -59
- package/docs/sections/header.md +0 -3
- package/docs/sections/installation/full.md +0 -6
- package/docs/sections/jobs/full.md +0 -140
- package/docs/sections/jobs/overview.md +0 -15
- package/docs/sections/logging/full.md +0 -83
- package/docs/sections/metrics/full.md +0 -131
- package/docs/sections/mongodb-connections/full.md +0 -45
- package/docs/sections/mongodb-connections/overview.md +0 -7
- package/docs/sections/multi-tenancy/full.md +0 -66
- package/docs/sections/multi-tenancy/overview.md +0 -15
- package/docs/sections/oauth/full.md +0 -189
- package/docs/sections/oauth/overview.md +0 -16
- package/docs/sections/package-development/full.md +0 -7
- package/docs/sections/pagination/full.md +0 -93
- package/docs/sections/passkey-login/full.md +0 -90
- package/docs/sections/passkey-login/overview.md +0 -1
- package/docs/sections/peer-dependencies/full.md +0 -47
- package/docs/sections/quick-start/full.md +0 -43
- package/docs/sections/response-caching/full.md +0 -117
- package/docs/sections/response-caching/overview.md +0 -13
- package/docs/sections/roles/full.md +0 -225
- package/docs/sections/roles/overview.md +0 -14
- package/docs/sections/running-without-redis/full.md +0 -16
- package/docs/sections/running-without-redis-or-mongodb/full.md +0 -60
- package/docs/sections/signing/full.md +0 -203
- package/docs/sections/stack/full.md +0 -10
- package/docs/sections/uploads/full.md +0 -208
- package/docs/sections/versioning/full.md +0 -85
- package/docs/sections/webhook-auth/full.md +0 -100
- package/docs/sections/websocket/full.md +0 -196
- package/docs/sections/websocket/overview.md +0 -5
- package/docs/sections/websocket-rooms/full.md +0 -102
- package/docs/sections/websocket-rooms/overview.md +0 -5
- /package/dist/{lib/storageAdapter.js → packages/bunshot-admin/src/types/env.js} +0 -0
- /package/dist/{lib → packages/bunshot-auth/src/lib}/fingerprint.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-auth/src/lib}/logger.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/constants.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/storageAdapter.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/createDtoMapper.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.js +0 -0
- /package/dist/{middleware → src/framework/middleware}/index.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/logger.js +0 -0
- /package/dist/{lib → src/shared/lib}/constants.js +0 -0
|
@@ -1,790 +0,0 @@
|
|
|
1
|
-
### Auth Flow
|
|
2
|
-
|
|
3
|
-
Sessions are backed by Redis by default. Each login creates an independent session keyed by a UUID (`session:{appName}:{sessionId}`), so multiple devices / tabs can be logged in simultaneously. Set `db.sessions: "mongo"` to store them in MongoDB instead — useful when running without Redis. See [Running without Redis](#running-without-redis).
|
|
4
|
-
|
|
5
|
-
#### Browser clients
|
|
6
|
-
1. `POST /auth/login` → JWT set as HttpOnly cookie automatically
|
|
7
|
-
2. All subsequent requests send the cookie — no extra code needed
|
|
8
|
-
|
|
9
|
-
#### API / non-browser clients
|
|
10
|
-
1. `POST /auth/login` → read `token` from response body
|
|
11
|
-
2. Send `x-user-token: <token>` header on every request
|
|
12
|
-
|
|
13
|
-
#### Current user
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
GET /auth/me → { userId, email?, emailVerified?, googleLinked? }
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Requires an active session (cookie or `x-user-token` header). Returns the authenticated user's profile — `email`, `emailVerified`, and `googleLinked` are populated when the auth adapter implements `getUser`.
|
|
20
|
-
|
|
21
|
-
#### Session management
|
|
22
|
-
|
|
23
|
-
Each login creates an independent session so multiple devices stay logged in simultaneously. The framework enforces a configurable cap (default: 6) — the oldest session is evicted when the limit is exceeded.
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
GET /auth/sessions → [{ sessionId, createdAt, lastActiveAt, expiresAt, ipAddress, userAgent, isActive }]
|
|
27
|
-
DELETE /auth/sessions/:sessionId → revoke a specific session (other sessions unaffected)
|
|
28
|
-
POST /auth/logout → revoke only the current session
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Session metadata (IP address, user-agent, timestamps) is persisted even after a session expires when `sessionPolicy.persistSessionMetadata: true` (default). This enables tenant apps to detect logins from novel devices or locations and prompt for MFA or send a security alert.
|
|
32
|
-
|
|
33
|
-
Set `sessionPolicy.includeInactiveSessions: true` to surface expired/deleted sessions in `GET /auth/sessions` with `isActive: false` — useful for a full device-history UI similar to Google or Meta's account security page.
|
|
34
|
-
|
|
35
|
-
##### Sliding sessions
|
|
36
|
-
|
|
37
|
-
Set `sessionPolicy.trackLastActive: true` to update `lastActiveAt` on every authenticated request. This adds one DB write per request but enables a sliding-session experience — sessions that are actively used stay fresh. Pair with refresh tokens (below) for true sliding behavior: short-lived access tokens (15 min) keep authorization tight, while a long-lived refresh token (30 days) lets the client silently renew without re-entering credentials.
|
|
38
|
-
|
|
39
|
-
#### Refresh Tokens
|
|
40
|
-
|
|
41
|
-
When configured, login and register return short-lived access tokens (default 15 min) alongside long-lived refresh tokens (default 30 days). The client uses `POST /auth/refresh` to obtain a new access token when the current one expires.
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
await createServer({
|
|
45
|
-
auth: {
|
|
46
|
-
refreshTokens: {
|
|
47
|
-
accessTokenExpiry: 900, // seconds, default: 900 (15 min)
|
|
48
|
-
refreshTokenExpiry: 2_592_000, // seconds, default: 2_592_000 (30 days)
|
|
49
|
-
rotationGraceSeconds: 30, // default: 30 — old token still works briefly after rotation
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**When not configured**, the existing 7-day JWT behavior is unchanged — fully backward compatible.
|
|
56
|
-
|
|
57
|
-
##### Endpoints
|
|
58
|
-
|
|
59
|
-
| Endpoint | Purpose |
|
|
60
|
-
|---|---|
|
|
61
|
-
| `POST /auth/login` | Returns `token` + `refreshToken` |
|
|
62
|
-
| `POST /auth/register` | Returns `token` + `refreshToken` |
|
|
63
|
-
| `POST /auth/refresh` | Rotates refresh token, returns new `token` + `refreshToken` |
|
|
64
|
-
|
|
65
|
-
##### Rotation with grace window
|
|
66
|
-
|
|
67
|
-
On each refresh, the server generates a new refresh token but keeps the old one valid for `rotationGraceSeconds` (default 30s). If the client's network drops mid-refresh, it can safely retry with the old token. If the old token is reused *after* the grace window, the entire session is invalidated — this is token-family theft detection.
|
|
68
|
-
|
|
69
|
-
##### Cookie behavior
|
|
70
|
-
|
|
71
|
-
The refresh token is set as an `HttpOnly` cookie (`refresh_token`) alongside the existing session cookie. For non-browser clients, it is accepted via the `x-refresh-token` header or in the request body. **The refresh token is not returned in the JSON response body** — it is only delivered via the `HttpOnly` cookie to prevent accidental exposure in logs or client-side code.
|
|
72
|
-
|
|
73
|
-
#### MFA / TOTP
|
|
74
|
-
|
|
75
|
-
Enable multi-factor authentication with TOTP (Google Authenticator, Authy, etc.):
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
await createServer({
|
|
79
|
-
auth: {
|
|
80
|
-
mfa: {
|
|
81
|
-
issuer: "My App", // shown in authenticator apps (default: app name)
|
|
82
|
-
algorithm: "SHA1", // default, most compatible
|
|
83
|
-
digits: 6, // default
|
|
84
|
-
period: 30, // seconds, default
|
|
85
|
-
recoveryCodes: 10, // number of recovery codes, default: 10
|
|
86
|
-
challengeTtlSeconds: 300, // MFA challenge window, default: 5 min
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Requires `otpauth` peer dependency:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
bun add otpauth
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
##### Endpoints
|
|
99
|
-
|
|
100
|
-
| Endpoint | Auth | Purpose |
|
|
101
|
-
|---|---|---|
|
|
102
|
-
| `POST /auth/mfa/setup` | userAuth | Generate TOTP secret + otpauth URI (for QR code) |
|
|
103
|
-
| `POST /auth/mfa/verify-setup` | userAuth | Confirm with TOTP code, returns recovery codes |
|
|
104
|
-
| `POST /auth/mfa/verify` | none (uses mfaToken) | Complete login after password verified |
|
|
105
|
-
| `DELETE /auth/mfa` | userAuth | Disable all MFA (requires TOTP code) |
|
|
106
|
-
| `POST /auth/mfa/recovery-codes` | userAuth | Regenerate codes (requires TOTP code) |
|
|
107
|
-
| `GET /auth/mfa/methods` | userAuth | Get enabled MFA methods |
|
|
108
|
-
|
|
109
|
-
##### Login flow with MFA enabled
|
|
110
|
-
|
|
111
|
-
1. `POST /auth/login` with credentials → password OK + MFA enabled → `{ mfaRequired: true, mfaToken: "...", mfaMethods: ["totp"] }` (no session created)
|
|
112
|
-
2. `POST /auth/mfa/verify` with `{ mfaToken, code }` → verifies TOTP or recovery code → creates session → returns normal token response
|
|
113
|
-
|
|
114
|
-
The verify endpoint accepts an optional `method` field (`"totp"` or `"emailOtp"`) to target a specific verification method. When omitted, methods are tried automatically.
|
|
115
|
-
|
|
116
|
-
**OAuth logins skip MFA** — the OAuth provider is treated as the second factor.
|
|
117
|
-
|
|
118
|
-
**Recovery codes**: 10 random 8-character alphanumeric codes, stored as SHA-256 hashes. Each code can only be used once. Enabling a second MFA method regenerates recovery codes — save the new set.
|
|
119
|
-
|
|
120
|
-
##### Enforcing MFA for all users
|
|
121
|
-
|
|
122
|
-
By default MFA is opt-in — individual users choose whether to enable it. Set `required: true` to enforce MFA at the app level:
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
await createServer({
|
|
126
|
-
auth: {
|
|
127
|
-
mfa: {
|
|
128
|
-
issuer: "My App",
|
|
129
|
-
required: true, // all authenticated users must complete MFA setup
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
When `required` is `true`:
|
|
136
|
-
|
|
137
|
-
- Authenticated users who have **not** completed MFA setup receive a `403` response on all non-auth endpoints:
|
|
138
|
-
```json
|
|
139
|
-
{ "error": "MFA setup required", "code": "MFA_SETUP_REQUIRED" }
|
|
140
|
-
```
|
|
141
|
-
- **Exempt paths** remain accessible so users can complete setup: all `/auth/*` routes (login, logout, register, MFA setup, OAuth, sessions), `/health`, `/docs`, `/openapi.json`, and the root `/`.
|
|
142
|
-
- **Unauthenticated requests** pass through normally — the middleware only gates users who are logged in but lack MFA.
|
|
143
|
-
- **OAuth users** must also set up MFA — OAuth login creates a session, but the user is still blocked from service endpoints until MFA is configured.
|
|
144
|
-
- **Disabling MFA** (via `DELETE /auth/mfa`) when `required: true` immediately blocks the user from service endpoints until they re-enable it.
|
|
145
|
-
|
|
146
|
-
**Client-side handling:** Check for the `MFA_SETUP_REQUIRED` code in 403 responses and redirect users to an MFA setup page that calls `POST /auth/mfa/setup`.
|
|
147
|
-
|
|
148
|
-
**Per-route usage:** The `requireMfaSetup` middleware is also exported for apps that want manual, per-route enforcement instead of global:
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
import { userAuth, requireMfaSetup } from "@lastshotlabs/bunshot";
|
|
152
|
-
|
|
153
|
-
router.get("/dashboard", userAuth, requireMfaSetup, (c) => {
|
|
154
|
-
return c.json({ message: "Welcome" });
|
|
155
|
-
});
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
#### Email OTP
|
|
159
|
-
|
|
160
|
-
An alternative to TOTP that sends a one-time code to the user's email. Users can enable TOTP, email OTP, or both.
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
await createServer({
|
|
164
|
-
auth: {
|
|
165
|
-
mfa: {
|
|
166
|
-
challengeTtlSeconds: 300,
|
|
167
|
-
emailOtp: {
|
|
168
|
-
onSend: async (email, code) => {
|
|
169
|
-
await sendEmail(email, `Your login code: ${code}`);
|
|
170
|
-
},
|
|
171
|
-
codeLength: 6, // default
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
##### Endpoints
|
|
179
|
-
|
|
180
|
-
| Endpoint | Auth | Purpose |
|
|
181
|
-
|---|---|---|
|
|
182
|
-
| `POST /auth/mfa/email-otp/enable` | userAuth | Send verification code to email |
|
|
183
|
-
| `POST /auth/mfa/email-otp/verify-setup` | userAuth | Confirm code, enable email OTP |
|
|
184
|
-
| `DELETE /auth/mfa/email-otp` | userAuth | Disable email OTP |
|
|
185
|
-
| `POST /auth/mfa/resend` | none (uses mfaToken) | Resend email OTP code (max 3 per challenge) |
|
|
186
|
-
|
|
187
|
-
##### Setup flow
|
|
188
|
-
|
|
189
|
-
1. `POST /auth/mfa/email-otp/enable` → sends code to email → returns `{ setupToken }`
|
|
190
|
-
2. `POST /auth/mfa/email-otp/verify-setup` with `{ setupToken, code }` → enables email OTP → returns recovery codes
|
|
191
|
-
|
|
192
|
-
This two-step flow ensures the `onSend` callback actually delivers emails before MFA is activated, preventing lockout from misconfigured email providers.
|
|
193
|
-
|
|
194
|
-
##### Login flow with email OTP
|
|
195
|
-
|
|
196
|
-
1. `POST /auth/login` → `{ mfaRequired: true, mfaToken, mfaMethods: ["emailOtp"] }` — code is auto-sent to user's email
|
|
197
|
-
2. `POST /auth/mfa/verify` with `{ mfaToken, code }` → creates session
|
|
198
|
-
3. If the code didn't arrive: `POST /auth/mfa/resend` with `{ mfaToken }` (max 3 resends, capped at 3x challenge TTL)
|
|
199
|
-
|
|
200
|
-
##### Disabling email OTP
|
|
201
|
-
|
|
202
|
-
- If TOTP is also enabled: requires a TOTP code in the `code` field
|
|
203
|
-
- If email OTP is the only method: requires the account password in the `password` field
|
|
204
|
-
- Disabling the last MFA method turns off MFA entirely
|
|
205
|
-
|
|
206
|
-
#### WebAuthn / Security Keys
|
|
207
|
-
|
|
208
|
-
Hardware security keys (YubiKey, etc.) and platform authenticators (Touch ID, Windows Hello) via the WebAuthn/FIDO2 standard. Users can register multiple keys and use them as an MFA method alongside TOTP and email OTP.
|
|
209
|
-
|
|
210
|
-
```ts
|
|
211
|
-
await createServer({
|
|
212
|
-
auth: {
|
|
213
|
-
mfa: {
|
|
214
|
-
webauthn: {
|
|
215
|
-
rpId: "example.com", // Relying Party ID — your domain
|
|
216
|
-
origin: "https://example.com", // Expected origin(s)
|
|
217
|
-
rpName: "My App", // Display name (default: app name)
|
|
218
|
-
userVerification: "preferred", // "required" | "preferred" | "discouraged"
|
|
219
|
-
timeout: 60000, // Ceremony timeout in ms (default: 60000)
|
|
220
|
-
strictSignCount: false, // Reject when sign count goes backward (default: false — warn only)
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Requires `@simplewebauthn/server` peer dependency:
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
bun add @simplewebauthn/server
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
If `mfa.webauthn` is configured but the dependency is missing, the server fails fast at startup with a clear error message.
|
|
234
|
-
|
|
235
|
-
##### Endpoints
|
|
236
|
-
|
|
237
|
-
| Endpoint | Auth | Purpose |
|
|
238
|
-
|---|---|---|
|
|
239
|
-
| `POST /auth/mfa/webauthn/register-options` | userAuth | Generate registration options for `navigator.credentials.create()` |
|
|
240
|
-
| `POST /auth/mfa/webauthn/register` | userAuth | Verify attestation and store credential |
|
|
241
|
-
| `GET /auth/mfa/webauthn/credentials` | userAuth | List registered security keys |
|
|
242
|
-
| `DELETE /auth/mfa/webauthn/credentials/:credentialId` | userAuth | Remove a single key |
|
|
243
|
-
| `DELETE /auth/mfa/webauthn` | userAuth | Disable WebAuthn entirely |
|
|
244
|
-
|
|
245
|
-
##### Registration flow
|
|
246
|
-
|
|
247
|
-
1. `POST /auth/mfa/webauthn/register-options` → returns `{ options, registrationToken }`
|
|
248
|
-
2. Client passes `options` to `navigator.credentials.create()` — browser prompts user to tap/scan key
|
|
249
|
-
3. `POST /auth/mfa/webauthn/register` with `{ registrationToken, attestationResponse, name? }` → stores credential → returns recovery codes
|
|
250
|
-
|
|
251
|
-
> Credentials are registered with `residentKey: "required"` and `userVerification: "required"`, making them usable as discoverable passkeys. This enables passwordless login via `allowPasswordlessLogin` without requiring users to re-register.
|
|
252
|
-
|
|
253
|
-
##### Login flow with WebAuthn
|
|
254
|
-
|
|
255
|
-
1. `POST /auth/login` → `{ mfaRequired: true, mfaToken, mfaMethods: ["webauthn"], webauthnOptions: {...} }`
|
|
256
|
-
2. Client passes `webauthnOptions` to `navigator.credentials.get()` — browser prompts for key
|
|
257
|
-
3. `POST /auth/mfa/verify` with `{ mfaToken, webauthnResponse: {...} }` → creates session
|
|
258
|
-
|
|
259
|
-
The `webauthnOptions` object follows the WebAuthn spec — pass it directly to `navigator.credentials.get()`. The `webauthnResponse` is the full result from the browser API.
|
|
260
|
-
|
|
261
|
-
##### Credential removal
|
|
262
|
-
|
|
263
|
-
- Removing a spare key (other keys or MFA methods still active): no extra verification needed
|
|
264
|
-
- Removing the last credential of the last MFA method: requires TOTP code or password
|
|
265
|
-
- `DELETE /auth/mfa/webauthn` (disable all): always requires verification
|
|
266
|
-
|
|
267
|
-
##### Sign count validation
|
|
268
|
-
|
|
269
|
-
WebAuthn authenticators increment a sign count on each use to detect cloned keys. By default, a backward count logs a warning but allows authentication. Set `strictSignCount: true` to reject authentication when the count goes backward.
|
|
270
|
-
|
|
271
|
-
#### Email Verification
|
|
272
|
-
|
|
273
|
-
Opt-in via `auth.emailVerification`. Requires `primaryField: "email"` (default).
|
|
274
|
-
|
|
275
|
-
```ts
|
|
276
|
-
await createServer({
|
|
277
|
-
auth: {
|
|
278
|
-
emailVerification: {
|
|
279
|
-
onSend: async (email, token) => {
|
|
280
|
-
// Send via any provider (Resend, SendGrid, etc.)
|
|
281
|
-
await sendEmail(email, `Verify your email: https://myapp.com/verify?token=${token}`);
|
|
282
|
-
},
|
|
283
|
-
required: true, // Block login until verified (default: false)
|
|
284
|
-
tokenExpiry: 86400, // Seconds — default: 86400 (24 hours)
|
|
285
|
-
},
|
|
286
|
-
},
|
|
287
|
-
});
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
When configured, two routes are mounted:
|
|
291
|
-
|
|
292
|
-
| Endpoint | Auth | Purpose |
|
|
293
|
-
|---|---|---|
|
|
294
|
-
| `POST /auth/verify-email` | none | Consume verification token |
|
|
295
|
-
| `POST /auth/resend-verification` | none (uses credentials) | Resend verification email |
|
|
296
|
-
|
|
297
|
-
A verification token is sent automatically on registration via `emailVerification.onSend`. The token is SHA-256 hashed before storage. Rate-limited by IP (verify) and identifier (resend).
|
|
298
|
-
|
|
299
|
-
When `required: true`, unverified users receive `403 { error: "Email not verified" }` on `/auth/login`.
|
|
300
|
-
|
|
301
|
-
#### Password Reset
|
|
302
|
-
|
|
303
|
-
Opt-in via `auth.passwordReset`. Requires `primaryField: "email"` (default) and a `setPassword` implementation on your auth adapter.
|
|
304
|
-
|
|
305
|
-
```ts
|
|
306
|
-
await createServer({
|
|
307
|
-
auth: {
|
|
308
|
-
passwordReset: {
|
|
309
|
-
onSend: async (email, token) => {
|
|
310
|
-
await sendEmail(email, `Reset your password: https://myapp.com/reset?token=${token}`);
|
|
311
|
-
},
|
|
312
|
-
tokenExpiry: 3600, // Seconds — default: 3600 (1 hour)
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
When configured, two routes are mounted:
|
|
319
|
-
|
|
320
|
-
| Endpoint | Auth | Purpose |
|
|
321
|
-
|---|---|---|
|
|
322
|
-
| `POST /auth/forgot-password` | none | Request reset email (always returns 200 — never reveals whether address is registered) |
|
|
323
|
-
| `POST /auth/reset-password` | none | Consume token, set new password, revoke all sessions |
|
|
324
|
-
|
|
325
|
-
The forgot-password endpoint uses a fire-and-forget pattern and is rate-limited by **both IP and email address** to prevent distributed email-bombing. Tokens are SHA-256 hashed before storage and single-use. After a successful reset, all active sessions are revoked.
|
|
326
|
-
|
|
327
|
-
#### Primary Field
|
|
328
|
-
|
|
329
|
-
By default, users register and log in with their email address. Change this via `auth.primaryField`:
|
|
330
|
-
|
|
331
|
-
```ts
|
|
332
|
-
await createServer({
|
|
333
|
-
auth: {
|
|
334
|
-
primaryField: "username", // "email" (default) | "username" | "phone"
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
When set to `"username"` or `"phone"`, the registration/login body uses that field name instead of `email`. Email verification and password reset are only available when `primaryField` is `"email"`. Implement `adapter.findByIdentifier` on your custom adapter for non-email primary fields — it falls back to `findByEmail` when absent.
|
|
340
|
-
|
|
341
|
-
#### Account Deletion
|
|
342
|
-
|
|
343
|
-
Enable `DELETE /auth/me` for user-initiated account deletion:
|
|
344
|
-
|
|
345
|
-
```ts
|
|
346
|
-
await createServer({
|
|
347
|
-
auth: {
|
|
348
|
-
accountDeletion: {
|
|
349
|
-
onBeforeDelete: async (userId) => {
|
|
350
|
-
// Throw to abort (e.g., check for active subscription)
|
|
351
|
-
},
|
|
352
|
-
onAfterDelete: async (userId) => {
|
|
353
|
-
// Cleanup: delete S3 files, cancel Stripe, etc.
|
|
354
|
-
// Runs at execution time — query current state, not a snapshot
|
|
355
|
-
},
|
|
356
|
-
queued: false, // set true for async deletion via BullMQ
|
|
357
|
-
gracePeriod: 0, // seconds before queued deletion executes
|
|
358
|
-
onDeletionScheduled: async (userId, email, cancelToken) => {
|
|
359
|
-
// Send cancellation email with cancelToken link
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
##### Behavior
|
|
367
|
-
|
|
368
|
-
- Requires `userAuth` middleware (user must be logged in)
|
|
369
|
-
- Body: `{ password?: string }` — required for credential accounts, skipped for OAuth-only
|
|
370
|
-
- Revokes all sessions, deletes tokens, calls `adapter.deleteUser(userId)`
|
|
371
|
-
- Rate limited (3/hour by userId)
|
|
372
|
-
|
|
373
|
-
##### Queued deletion
|
|
374
|
-
|
|
375
|
-
When `queued: true`, deletion is enqueued as a BullMQ job instead of running synchronously. The endpoint returns `202 Accepted` immediately and the user's sessions are revoked at that point. The actual user data deletion executes after the delay set by `gracePeriod`.
|
|
376
|
-
|
|
377
|
-
The framework starts a built-in BullMQ worker automatically (in-process, alongside the API server) to process deletion jobs. Requires BullMQ and Redis:
|
|
378
|
-
|
|
379
|
-
```bash
|
|
380
|
-
bun add bullmq
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
With `gracePeriod > 0`, the `POST /auth/cancel-deletion` route is mounted. Provide `onDeletionScheduled` to send the cancel token to the user:
|
|
384
|
-
|
|
385
|
-
```ts
|
|
386
|
-
auth: {
|
|
387
|
-
accountDeletion: {
|
|
388
|
-
queued: true,
|
|
389
|
-
gracePeriod: 7 * 24 * 60 * 60, // 7 days in seconds
|
|
390
|
-
onDeletionScheduled: async (userId, email, cancelToken) => {
|
|
391
|
-
await sendEmail(email, `Cancel deletion: https://myapp.com/cancel?token=${cancelToken}`);
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
The cancel endpoint accepts the token and removes the pending BullMQ job:
|
|
398
|
-
|
|
399
|
-
```
|
|
400
|
-
POST /auth/cancel-deletion → { message: "Account deletion cancelled" }
|
|
401
|
-
Body: { token: string }
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
The cancel token expires when the grace period elapses and can only be used once.
|
|
405
|
-
|
|
406
|
-
#### Password Policy
|
|
407
|
-
|
|
408
|
-
Configure password complexity requirements via `auth.passwordPolicy`. The policy applies to registration and password reset — login uses `min(1)` intentionally to avoid locking out users registered under older/weaker policies.
|
|
409
|
-
|
|
410
|
-
```ts
|
|
411
|
-
await createServer({
|
|
412
|
-
auth: {
|
|
413
|
-
passwordPolicy: {
|
|
414
|
-
minLength: 10, // default: 8
|
|
415
|
-
requireLetter: true, // default: true — at least one a–z or A–Z
|
|
416
|
-
requireDigit: true, // default: true — at least one 0–9
|
|
417
|
-
requireSpecial: true, // default: false — at least one non-alphanumeric character
|
|
418
|
-
},
|
|
419
|
-
},
|
|
420
|
-
});
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
When not configured, the default policy requires 8+ characters with at least one letter and one digit.
|
|
424
|
-
|
|
425
|
-
#### Protecting routes
|
|
426
|
-
|
|
427
|
-
```ts
|
|
428
|
-
import { userAuth, requireRole, requireVerifiedEmail } from "@lastshotlabs/bunshot";
|
|
429
|
-
|
|
430
|
-
router.use("/my-route", userAuth); // returns 401 if not logged in
|
|
431
|
-
router.use("/admin", userAuth, requireRole("admin")); // returns 403 if user lacks role
|
|
432
|
-
router.use("/content", userAuth, requireRole("admin", "editor")); // allow either role
|
|
433
|
-
router.use("/dashboard", userAuth, requireVerifiedEmail); // returns 403 if email not verified
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
#### Custom auth adapter
|
|
437
|
-
|
|
438
|
-
By default, `/auth/*` routes store users in MongoDB via `mongoAuthAdapter`. Pass `auth: { adapter: myAdapter }` to `createServer` to use any other store — Postgres, SQLite, an external service, etc. Alternatively, use `db.auth` to select a built-in adapter (`"mongo"` | `"sqlite"` | `"memory"`).
|
|
439
|
-
|
|
440
|
-
The schema should include a `roles` column if you plan to use role-based access:
|
|
441
|
-
|
|
442
|
-
```sql
|
|
443
|
-
-- roles stored as a text array in Postgres
|
|
444
|
-
ALTER TABLE users ADD COLUMN roles text[] NOT NULL DEFAULT '{}';
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
```ts
|
|
448
|
-
import type { AuthAdapter } from "@lastshotlabs/bunshot";
|
|
449
|
-
import { HttpError } from "@lastshotlabs/bunshot";
|
|
450
|
-
import { db } from "./db";
|
|
451
|
-
import { users } from "./schema";
|
|
452
|
-
import { eq, sql } from "drizzle-orm";
|
|
453
|
-
|
|
454
|
-
const pgAuthAdapter: AuthAdapter = {
|
|
455
|
-
async findByEmail(email) {
|
|
456
|
-
const user = await db.query.users.findFirst({ where: eq(users.email, email) });
|
|
457
|
-
return user ? { id: user.id, passwordHash: user.passwordHash } : null;
|
|
458
|
-
},
|
|
459
|
-
async create(email, passwordHash) {
|
|
460
|
-
try {
|
|
461
|
-
const [user] = await db.insert(users).values({ email, passwordHash }).returning({ id: users.id });
|
|
462
|
-
return { id: user.id };
|
|
463
|
-
} catch (err: any) {
|
|
464
|
-
if (/* unique constraint */ err.code === "23505") throw new HttpError(409, "Email already registered");
|
|
465
|
-
throw err;
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
// --- Role methods (optional — only needed if using roles / requireRole) ---
|
|
469
|
-
async getRoles(userId) {
|
|
470
|
-
const user = await db.query.users.findFirst({ where: eq(users.id, userId) });
|
|
471
|
-
return user?.roles ?? [];
|
|
472
|
-
},
|
|
473
|
-
async setRoles(userId, roles) { // required if using defaultRole
|
|
474
|
-
await db.update(users).set({ roles }).where(eq(users.id, userId));
|
|
475
|
-
},
|
|
476
|
-
async addRole(userId, role) {
|
|
477
|
-
await db.update(users)
|
|
478
|
-
.set({ roles: sql`array_append(roles, ${role})` })
|
|
479
|
-
.where(eq(users.id, userId));
|
|
480
|
-
},
|
|
481
|
-
async removeRole(userId, role) {
|
|
482
|
-
await db.update(users)
|
|
483
|
-
.set({ roles: sql`array_remove(roles, ${role})` })
|
|
484
|
-
.where(eq(users.id, userId));
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
await createServer({
|
|
489
|
-
routesDir: import.meta.dir + "/routes",
|
|
490
|
-
app: { name: "My App", version: "1.0.0" },
|
|
491
|
-
auth: {
|
|
492
|
-
roles: ["admin", "editor", "user"],
|
|
493
|
-
defaultRole: "user",
|
|
494
|
-
adapter: pgAuthAdapter,
|
|
495
|
-
},
|
|
496
|
-
});
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
The adapter is responsible for:
|
|
500
|
-
- `findByEmail` — return `{ id, passwordHash }` or `null` if not found
|
|
501
|
-
- `create` — insert the user and return `{ id }`, throw `HttpError(409, ...)` on duplicate email
|
|
502
|
-
- `setPassword` _(optional)_ — update the stored password hash for `userId`; implement to enable `POST /auth/set-password`
|
|
503
|
-
- `findOrCreateByProvider` _(optional)_ — required for OAuth social login
|
|
504
|
-
- `linkProvider` _(optional)_ — add a provider identity to an existing user; implement to enable `GET /auth/{provider}/link`
|
|
505
|
-
- `unlinkProvider` _(optional)_ — remove all identities for a provider from a user; implement to enable `DELETE /auth/{provider}/link`
|
|
506
|
-
- `getRoles` _(optional)_ — return the roles assigned to `userId`; implement to enable `requireRole` middleware
|
|
507
|
-
- `setRoles` _(optional)_ — replace all roles; required if using `defaultRole`
|
|
508
|
-
- `addRole` _(optional)_ — add a single role; implement to use `addUserRole`
|
|
509
|
-
- `removeRole` _(optional)_ — remove a single role; implement to use `removeUserRole`
|
|
510
|
-
- `getUser` _(optional)_ — return `{ email?, providerIds?, emailVerified? }` for `userId`; implement to populate `GET /auth/me` (including `googleLinked` and `emailVerified`)
|
|
511
|
-
- `findByIdentifier` _(optional)_ — look up a user by the configured `primaryField` value; implement for non-email primary fields. Falls back to `findByEmail` if absent.
|
|
512
|
-
- `setEmailVerified` _(optional)_ — mark a user as email-verified; implement to support `POST /auth/verify-email`
|
|
513
|
-
- `getEmailVerified` _(optional)_ — return whether a user is email-verified; implement to support the `emailVerification.required` gate and `POST /auth/resend-verification`
|
|
514
|
-
|
|
515
|
-
Everything else (password hashing, JWT signing, Redis sessions) is handled by the package.
|
|
516
|
-
|
|
517
|
-
#### Auth Rate Limiting
|
|
518
|
-
|
|
519
|
-
All built-in auth endpoints are rate-limited out of the box with sensible defaults. No configuration needed — just be aware of the behavior:
|
|
520
|
-
|
|
521
|
-
| Endpoint | Key | Counts | Default limit |
|
|
522
|
-
|---|---|---|---|
|
|
523
|
-
| `POST /auth/login` | identifier (email/username/phone) | **Failures only** — reset on success | 10 failures / 15 min |
|
|
524
|
-
| `POST /auth/register` | IP address | Every attempt | 5 / hour |
|
|
525
|
-
| `POST /auth/verify-email` | IP address | Every attempt | 10 / 15 min |
|
|
526
|
-
| `POST /auth/resend-verification` | Identifier (email/username/phone) | Every attempt | 3 / hour |
|
|
527
|
-
| `POST /auth/forgot-password` | IP address **and** email address | Every attempt | 5 / 15 min (shared window per key) |
|
|
528
|
-
| `POST /auth/reset-password` | IP address | Every attempt | 10 / 15 min |
|
|
529
|
-
| `POST /auth/refresh` | IP address | Every attempt | 30 / min |
|
|
530
|
-
| `POST /auth/mfa/verify` | IP address | Every attempt | 10 / 15 min |
|
|
531
|
-
| `POST /auth/mfa/resend` | IP address | Every attempt | 5 / min |
|
|
532
|
-
|
|
533
|
-
Login is keyed by the **identifier being targeted** — an attacker rotating IPs to brute-force `alice@example.com` is blocked regardless of source IP. A successful login resets the counter so legitimate users aren't locked out.
|
|
534
|
-
|
|
535
|
-
##### Tuning limits
|
|
536
|
-
|
|
537
|
-
```ts
|
|
538
|
-
await createServer({
|
|
539
|
-
auth: {
|
|
540
|
-
rateLimit: {
|
|
541
|
-
login: { windowMs: 10 * 60 * 1000, max: 5 }, // stricter: 5 failures / 10 min
|
|
542
|
-
register: { windowMs: 60 * 60 * 1000, max: 3 },
|
|
543
|
-
verifyEmail: { windowMs: 15 * 60 * 1000, max: 10 }, // leave at default
|
|
544
|
-
resendVerification: { windowMs: 60 * 60 * 1000, max: 2 },
|
|
545
|
-
store: "redis", // default when Redis is enabled — shared across all server instances
|
|
546
|
-
},
|
|
547
|
-
},
|
|
548
|
-
});
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
##### Manually clearing a limit (admin unlock)
|
|
552
|
-
|
|
553
|
-
If a legitimate user gets locked out, call `bustAuthLimit` with the same key format the limiter uses:
|
|
554
|
-
|
|
555
|
-
```ts
|
|
556
|
-
import { bustAuthLimit } from "@lastshotlabs/bunshot";
|
|
557
|
-
|
|
558
|
-
// Admin route: POST /admin/unblock-login
|
|
559
|
-
router.post("/admin/unblock-login", userAuth, requireRole("admin"), async (c) => {
|
|
560
|
-
const { identifier } = await c.req.json();
|
|
561
|
-
await bustAuthLimit(`login:${identifier}`);
|
|
562
|
-
return c.json({ message: "Login limit cleared" });
|
|
563
|
-
});
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
Key formats: `login:{identifier}`, `register:{ip}`, `verify:{ip}`, `resend:{identifier}`, `forgot:ip:{ip}`, `forgot:email:{email}`, `reset:{ip}`, `refresh:ip:{ip}`, `deleteaccount:{userId}`.
|
|
567
|
-
|
|
568
|
-
##### Using the rate limiter in your own routes
|
|
569
|
-
|
|
570
|
-
`trackAttempt` and `isLimited` are exported so you can apply the same Redis-backed rate limiting to any route in your app. They use the same store configured via `auth.rateLimit.store`.
|
|
571
|
-
|
|
572
|
-
```ts
|
|
573
|
-
import { trackAttempt, isLimited, bustAuthLimit, getClientIp } from "@lastshotlabs/bunshot";
|
|
574
|
-
|
|
575
|
-
// trackAttempt — increments the counter and returns true if now over the limit
|
|
576
|
-
// isLimited — checks without incrementing (read-only)
|
|
577
|
-
// bustAuthLimit — resets a key (e.g. on success or admin unlock)
|
|
578
|
-
|
|
579
|
-
router.post("/api/submit", async (c) => {
|
|
580
|
-
const ip = getClientIp(c);
|
|
581
|
-
const key = `submit:${ip}`;
|
|
582
|
-
|
|
583
|
-
if (await trackAttempt(key, { windowMs: 60 * 1000, max: 5 })) {
|
|
584
|
-
return c.json({ error: "Too many requests" }, 429);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// ... handle request
|
|
588
|
-
return c.json({ ok: true });
|
|
589
|
-
});
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
Use `isLimited` when you want to check the current state without counting the request itself — for example, to gate an expensive pre-check before the attempt is registered:
|
|
593
|
-
|
|
594
|
-
```ts
|
|
595
|
-
if (await isLimited(key, opts)) {
|
|
596
|
-
return c.json({ error: "Too many requests" }, 429);
|
|
597
|
-
}
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
Keys are automatically namespaced to the app (e.g. `rl:MyApp:submit:1.2.3.4`) when the Redis store is active, so they won't collide on a shared Redis instance.
|
|
601
|
-
|
|
602
|
-
##### Store
|
|
603
|
-
|
|
604
|
-
The rate limit store defaults to `"redis"` when Redis is enabled (recommended for multi-instance deployments — limits are shared across all servers). Falls back to `"memory"` automatically when Redis is disabled. In-memory limits don't persist across restarts.
|
|
605
|
-
|
|
606
|
-
---
|
|
607
|
-
|
|
608
|
-
#### Bot Protection
|
|
609
|
-
|
|
610
|
-
The built-in IP rate limiter is ineffective against bots that rotate IPs. The `botProtection` config adds two IP-rotation-resistant layers that run before the IP rate limit check.
|
|
611
|
-
|
|
612
|
-
##### Fingerprint rate limiting
|
|
613
|
-
|
|
614
|
-
When `fingerprintRateLimit: true`, every request is also rate-limited by an HTTP fingerprint — a 12-char hash derived from `User-Agent`, `Accept-*`, `Connection`, and the presence/absence of browser-only headers (`sec-fetch-*`, `sec-ch-ua-*`, `origin`, `referer`, etc.).
|
|
615
|
-
|
|
616
|
-
Bots that rotate IPs but use the same HTTP client (e.g. Python `requests`, `curl`, a headless browser) produce the same fingerprint and share a rate-limit bucket regardless of their source IP. Real browser sessions produce a different fingerprint from CLI tools, so they don't interfere with each other.
|
|
617
|
-
|
|
618
|
-
```ts
|
|
619
|
-
await createServer({
|
|
620
|
-
security: {
|
|
621
|
-
rateLimit: { windowMs: 60_000, max: 100 }, // applies to both IP and fingerprint buckets
|
|
622
|
-
botProtection: {
|
|
623
|
-
fingerprintRateLimit: true,
|
|
624
|
-
},
|
|
625
|
-
},
|
|
626
|
-
});
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
The fingerprint bucket uses the same window and max as `security.rateLimit`, and is stored in the same backend as `auth.rateLimit.store` (Redis by default, shared across all instances).
|
|
630
|
-
|
|
631
|
-
##### IP / CIDR blocklist
|
|
632
|
-
|
|
633
|
-
Block known datacenter ranges, proxy providers, or individual IPs outright. Matched requests receive a 403 before any other processing — no session lookup, no rate-limit increment.
|
|
634
|
-
|
|
635
|
-
```ts
|
|
636
|
-
await createServer({
|
|
637
|
-
security: {
|
|
638
|
-
botProtection: {
|
|
639
|
-
blockList: [
|
|
640
|
-
"198.51.100.0/24", // IPv4 CIDR
|
|
641
|
-
"203.0.113.42", // exact IPv4
|
|
642
|
-
"2001:db8::1", // exact IPv6
|
|
643
|
-
],
|
|
644
|
-
},
|
|
645
|
-
},
|
|
646
|
-
});
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
Both options can be combined. The middleware order is: blocklist → IP rate limit → fingerprint rate limit.
|
|
650
|
-
|
|
651
|
-
##### Apply `botProtection` to individual routes
|
|
652
|
-
|
|
653
|
-
`botProtection` is also exported for per-route use:
|
|
654
|
-
|
|
655
|
-
```ts
|
|
656
|
-
import { botProtection } from "@lastshotlabs/bunshot";
|
|
657
|
-
|
|
658
|
-
router.use("/api/submit", botProtection({ blockList: ["198.51.100.0/24"] }));
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
---
|
|
662
|
-
|
|
663
|
-
#### Trusted Proxy
|
|
664
|
-
|
|
665
|
-
By default, Bunshot uses the socket-level IP address for all rate limiting and session metadata — the `X-Forwarded-For` header is **ignored entirely**. This prevents attackers from spoofing IPs to bypass rate limits.
|
|
666
|
-
|
|
667
|
-
If your app runs behind a reverse proxy (nginx, Cloudflare, AWS ALB), configure `security.trustProxy` so the framework reads the real client IP from the `X-Forwarded-For` chain:
|
|
668
|
-
|
|
669
|
-
```ts
|
|
670
|
-
await createServer({
|
|
671
|
-
security: {
|
|
672
|
-
trustProxy: 1, // trust 1 proxy hop — use the second-to-last IP in X-Forwarded-For
|
|
673
|
-
// trustProxy: 2, // behind 2 proxies (e.g. Cloudflare → ALB → app)
|
|
674
|
-
// trustProxy: false, // default — use socket IP, ignore XFF entirely
|
|
675
|
-
},
|
|
676
|
-
});
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
The number represents how many trusted proxy hops sit between your app and the internet. With `trustProxy: N`, the framework takes the Nth-from-right entry in the `X-Forwarded-For` chain, skipping the N trusted proxies.
|
|
680
|
-
|
|
681
|
-
All rate limiting (auth, general, bot protection) and session metadata (IP in `GET /auth/sessions`) use the centralized `getClientIp(c)` utility, which respects this setting. It's also exported for use in your own routes:
|
|
682
|
-
|
|
683
|
-
```ts
|
|
684
|
-
import { getClientIp } from "@lastshotlabs/bunshot";
|
|
685
|
-
|
|
686
|
-
router.post("/api/action", async (c) => {
|
|
687
|
-
const ip = getClientIp(c); // respects trustProxy setting
|
|
688
|
-
// ...
|
|
689
|
-
});
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
#### JWT Secret Validation
|
|
693
|
-
|
|
694
|
-
JWT secrets are validated on first use. The framework throws a clear error if:
|
|
695
|
-
- The environment variable (`JWT_SECRET_DEV` or `JWT_SECRET_PROD`) is missing
|
|
696
|
-
- The secret is shorter than 32 characters
|
|
697
|
-
|
|
698
|
-
Generate a strong secret:
|
|
699
|
-
|
|
700
|
-
```bash
|
|
701
|
-
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
---
|
|
705
|
-
|
|
706
|
-
#### Setting a password after social login
|
|
707
|
-
|
|
708
|
-
If a user signed up via Google or Apple and later wants to add a password, send an authenticated request to `POST /auth/set-password`:
|
|
709
|
-
|
|
710
|
-
```ts
|
|
711
|
-
// Client (logged-in user) — first time setting a password (no currentPassword needed)
|
|
712
|
-
await fetch("/auth/set-password", {
|
|
713
|
-
method: "POST",
|
|
714
|
-
headers: { "Content-Type": "application/json", "x-user-token": token },
|
|
715
|
-
body: JSON.stringify({ password: "mynewpassword" }),
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
// Changing an existing password — currentPassword is required
|
|
719
|
-
await fetch("/auth/set-password", {
|
|
720
|
-
method: "POST",
|
|
721
|
-
headers: { "Content-Type": "application/json", "x-user-token": token },
|
|
722
|
-
body: JSON.stringify({ password: "mynewpassword", currentPassword: "oldpassword" }),
|
|
723
|
-
});
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
The built-in route hashes the password and calls `adapter.setPassword(userId, hash)`. If your adapter does not implement `setPassword`, the route returns `501 Not Implemented`.
|
|
727
|
-
|
|
728
|
-
**If the account already has a password set**, `currentPassword` must be provided. Missing it returns `400 { error: "Current password is required to change an existing password." }`. An incorrect `currentPassword` returns `401 { error: "Current password is incorrect." }`.
|
|
729
|
-
|
|
730
|
-
To support it with a custom adapter:
|
|
731
|
-
|
|
732
|
-
```ts
|
|
733
|
-
const myAdapter: AuthAdapter = {
|
|
734
|
-
findByEmail: ...,
|
|
735
|
-
create: ...,
|
|
736
|
-
async setPassword(userId, passwordHash) {
|
|
737
|
-
await db.update(users).set({ passwordHash }).where(eq(users.id, userId));
|
|
738
|
-
},
|
|
739
|
-
};
|
|
740
|
-
```
|
|
741
|
-
|
|
742
|
-
#### CSRF Protection
|
|
743
|
-
|
|
744
|
-
Opt-in via `security.csrf` — protects cookie-authenticated browser clients against cross-site request forgery attacks. Mobile apps and SPAs using header-based auth (`x-user-token`) are not affected and do not need CSRF.
|
|
745
|
-
|
|
746
|
-
```ts
|
|
747
|
-
await createServer({
|
|
748
|
-
security: {
|
|
749
|
-
csrf: {
|
|
750
|
-
enabled: true,
|
|
751
|
-
// exemptPaths: ["/webhooks/*"], // additional exempt paths
|
|
752
|
-
// checkOrigin: true, // validate Origin header (default: true)
|
|
753
|
-
},
|
|
754
|
-
},
|
|
755
|
-
});
|
|
756
|
-
```
|
|
757
|
-
|
|
758
|
-
**How it works:**
|
|
759
|
-
|
|
760
|
-
1. The first GET request sets a `csrf_token` cookie (non-HttpOnly, readable by JS)
|
|
761
|
-
2. The token is HMAC-SHA256 signed with the JWT secret to prevent forgery
|
|
762
|
-
3. For state-changing requests (POST/PUT/PATCH/DELETE), the client must send the cookie value back in the `x-csrf-token` header
|
|
763
|
-
4. The middleware validates the signature and compares the header to the cookie using timing-safe comparison
|
|
764
|
-
5. Requests without an auth cookie (`token`) skip validation — they are not vulnerable to CSRF
|
|
765
|
-
|
|
766
|
-
The CSRF cookie is refreshed on login, register, MFA verify, and OAuth exchange. It is cleared on logout.
|
|
767
|
-
|
|
768
|
-
**Client-side integration:**
|
|
769
|
-
|
|
770
|
-
```js
|
|
771
|
-
function getCsrfToken() {
|
|
772
|
-
return document.cookie
|
|
773
|
-
.split("; ")
|
|
774
|
-
.find(row => row.startsWith("csrf_token="))
|
|
775
|
-
?.split("=")[1];
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
// Include on all state-changing requests
|
|
779
|
-
fetch("/api/resource", {
|
|
780
|
-
method: "POST",
|
|
781
|
-
credentials: "include",
|
|
782
|
-
headers: {
|
|
783
|
-
"Content-Type": "application/json",
|
|
784
|
-
"X-CSRF-Token": getCsrfToken(),
|
|
785
|
-
},
|
|
786
|
-
body: JSON.stringify(data),
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
// After login, read the NEW csrf_token value (it's refreshed on auth state changes)
|
|
790
|
-
```
|