@baseplate-dev/plugin-auth 0.6.17 → 0.6.19
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 +54 -0
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/admin-crud-manage-roles-action.generator.d.ts +74 -0
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/index.d.ts +74 -0
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/template-renderers.d.ts +37 -0
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/typed-templates.d.ts +37 -0
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.js +1 -2
- package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.tsx +1 -1
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/admin-crud-reset-password-action.generator.d.ts +74 -0
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/index.d.ts +74 -0
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/template-renderers.d.ts +37 -0
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/typed-templates.d.ts +74 -0
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.js +1 -2
- package/dist/better-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.tsx +1 -1
- package/dist/better-auth/admin/generators/admin-crud-roles-column/admin-crud-roles-column.generator.d.ts +37 -0
- package/dist/better-auth/core/node.js +7 -8
- package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/index.d.ts +1 -0
- package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/ts-import-providers.d.ts +1 -0
- package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/ts-import-providers.js +1 -0
- package/dist/better-auth/generators/fastify/better-auth-module/better-auth-module.generator.d.ts +20 -3
- package/dist/better-auth/generators/fastify/better-auth-module/better-auth-module.generator.js +5 -24
- package/dist/better-auth/generators/fastify/better-auth-module/generated/index.d.ts +40 -2
- package/dist/better-auth/generators/fastify/better-auth-module/generated/template-renderers.d.ts +19 -1
- package/dist/better-auth/generators/fastify/better-auth-module/generated/template-renderers.js +6 -2
- package/dist/better-auth/generators/fastify/better-auth-module/generated/ts-import-providers.d.ts +1 -0
- package/dist/better-auth/generators/fastify/better-auth-module/generated/ts-import-providers.js +1 -0
- package/dist/better-auth/generators/fastify/better-auth-module/generated/typed-templates.d.ts +20 -1
- package/dist/better-auth/generators/fastify/better-auth-module/generated/typed-templates.js +4 -1
- package/dist/better-auth/generators/fastify/better-auth-module/templates/module/services/auth.ts +16 -8
- package/dist/better-auth/generators/react/better-auth-hooks/better-auth-hooks.generator.d.ts +1 -1
- package/dist/better-auth/generators/react/better-auth-hooks/generated/index.d.ts +5 -4
- package/dist/better-auth/generators/react/better-auth-hooks/generated/template-paths.d.ts +1 -1
- package/dist/better-auth/generators/react/better-auth-hooks/generated/template-paths.js +1 -1
- package/dist/better-auth/generators/react/better-auth-hooks/generated/ts-import-providers.d.ts +2 -1
- package/dist/better-auth/generators/react/better-auth-hooks/generated/ts-import-providers.js +2 -1
- package/dist/better-auth/generators/react/better-auth-hooks/generated/typed-templates.d.ts +6 -6
- package/dist/better-auth/generators/react/better-auth-hooks/generated/typed-templates.js +13 -13
- package/dist/better-auth/generators/react/better-auth-hooks/templates/src/hooks/{use-required-user-id.ts → use-user-id-or-throw.ts} +1 -1
- package/dist/better-auth/generators/react/better-auth-pages/better-auth-pages.generator.d.ts +37 -0
- package/dist/better-auth/generators/react/better-auth-pages/generated/index.d.ts +222 -0
- package/dist/better-auth/generators/react/better-auth-pages/generated/template-renderers.d.ts +37 -0
- package/dist/better-auth/generators/react/better-auth-pages/generated/typed-templates.d.ts +370 -0
- package/dist/better-auth/generators/react/better-auth-pages/templates/routes/forgot-password.tsx +1 -4
- package/dist/better-auth/generators/react/react-better-auth/generated/index.d.ts +77 -2
- package/dist/better-auth/generators/react/react-better-auth/generated/template-renderers.d.ts +38 -1
- package/dist/better-auth/generators/react/react-better-auth/generated/ts-import-providers.d.ts +1 -0
- package/dist/better-auth/generators/react/react-better-auth/generated/ts-import-providers.js +1 -0
- package/dist/better-auth/generators/react/react-better-auth/generated/typed-templates.d.ts +38 -1
- package/dist/better-auth/generators/react/react-better-auth/react-better-auth.generator.d.ts +38 -1
- package/dist/better-auth/generators/react/react-better-auth/templates/src/app/auth-loaded-gate.tsx +12 -3
- package/dist/local-auth/admin/common.js +6 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/admin-crud-invite-user-action.generator.d.ts +593 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/admin-crud-invite-user-action.generator.js +119 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/index.d.ts +602 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/index.js +11 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-paths.d.ts +12 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-paths.js +24 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-renderers.d.ts +307 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-renderers.js +45 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/typed-templates.d.ts +294 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/typed-templates.js +21 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/index.d.ts +2 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/index.js +2 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.d.ts +21 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.js +68 -0
- package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.tsx +122 -0
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/admin-crud-manage-roles-action.generator.d.ts +74 -0
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/index.d.ts +74 -0
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/template-renderers.d.ts +37 -0
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/typed-templates.d.ts +37 -0
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.js +1 -2
- package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.tsx +1 -1
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/admin-crud-reset-password-action.generator.d.ts +74 -0
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/index.d.ts +74 -0
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/template-renderers.d.ts +37 -0
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/typed-templates.d.ts +74 -0
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.js +1 -2
- package/dist/local-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.tsx +1 -1
- package/dist/local-auth/admin/generators/admin-crud-roles-column/admin-crud-roles-column.generator.d.ts +37 -0
- package/dist/local-auth/admin/node.js +13 -0
- package/dist/local-auth/admin/schema/invite-user-action.d.ts +12 -0
- package/dist/local-auth/admin/schema/invite-user-action.js +6 -0
- package/dist/local-auth/admin/web.js +8 -0
- package/dist/local-auth/core/common.js +7 -2
- package/dist/local-auth/core/components/local-auth-definition-editor.js +2 -1
- package/dist/local-auth/core/components/local-auth-web-app-settings-form.d.ts +9 -0
- package/dist/local-auth/core/components/local-auth-web-app-settings-form.js +11 -0
- package/dist/local-auth/core/generators/auth-email-password/auth-email-password.generator.d.ts +16 -7
- package/dist/local-auth/core/generators/auth-email-password/auth-email-password.generator.js +73 -16
- package/dist/local-auth/core/generators/auth-email-password/generated/index.d.ts +222 -7
- package/dist/local-auth/core/generators/auth-email-password/generated/template-paths.d.ts +5 -0
- package/dist/local-auth/core/generators/auth-email-password/generated/template-paths.js +5 -0
- package/dist/local-auth/core/generators/auth-email-password/generated/template-renderers.d.ts +27 -0
- package/dist/local-auth/core/generators/auth-email-password/generated/template-renderers.js +71 -4
- package/dist/local-auth/core/generators/auth-email-password/generated/ts-import-providers.d.ts +1 -3
- package/dist/local-auth/core/generators/auth-email-password/generated/ts-import-providers.js +1 -2
- package/dist/local-auth/core/generators/auth-email-password/generated/typed-templates.d.ts +226 -10
- package/dist/local-auth/core/generators/auth-email-password/generated/typed-templates.js +91 -7
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.d.ts +19 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.js +20 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.ts +22 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.d.ts +12 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.js +12 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.ts +14 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.d.ts +2 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.js +30 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.ts +38 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.d.ts +2 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.js +42 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.ts +54 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/user-password.mutations.js +2 -19
- package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/user-password.mutations.ts +1 -22
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.d.ts +37 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.js +225 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.ts +333 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-verification.service.js +2 -3
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-verification.service.ts +5 -3
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.d.ts +39 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.js +142 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.ts +221 -0
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/password-reset.service.js +5 -6
- package/dist/local-auth/core/generators/auth-email-password/templates/module/services/password-reset.service.ts +8 -5
- package/dist/local-auth/core/generators/auth-email-templates/auth-email-templates.generator.d.ts +3 -1
- package/dist/local-auth/core/generators/auth-email-templates/auth-email-templates.generator.js +18 -3
- package/dist/local-auth/core/generators/auth-email-templates/generated/index.d.ts +40 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/template-paths.d.ts +2 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/template-paths.js +2 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/template-renderers.d.ts +6 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/template-renderers.js +20 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/typed-templates.d.ts +40 -0
- package/dist/local-auth/core/generators/auth-email-templates/generated/typed-templates.js +24 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.d.ts +3 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.js +18 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.tsx +57 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.d.ts +3 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.js +14 -0
- package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.tsx +47 -0
- package/dist/local-auth/core/generators/auth-hooks/auth-hooks.generator.d.ts +272 -1
- package/dist/local-auth/core/generators/auth-hooks/generated/index.d.ts +547 -4
- package/dist/local-auth/core/generators/auth-hooks/generated/template-paths.d.ts +1 -1
- package/dist/local-auth/core/generators/auth-hooks/generated/template-paths.js +1 -1
- package/dist/local-auth/core/generators/auth-hooks/generated/template-renderers.d.ts +271 -0
- package/dist/local-auth/core/generators/auth-hooks/generated/template-renderers.js +4 -2
- package/dist/local-auth/core/generators/auth-hooks/generated/ts-import-providers.d.ts +2 -1
- package/dist/local-auth/core/generators/auth-hooks/generated/ts-import-providers.js +2 -1
- package/dist/local-auth/core/generators/auth-hooks/generated/typed-templates.d.ts +548 -6
- package/dist/local-auth/core/generators/auth-hooks/generated/typed-templates.js +15 -14
- package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-log-out.js +1 -1
- package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-log-out.ts +1 -1
- package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-session.d.ts +7 -0
- package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-session.ts +7 -0
- package/dist/local-auth/core/generators/auth-module/auth-module.generator.d.ts +23 -7
- package/dist/local-auth/core/generators/auth-module/auth-module.generator.js +7 -26
- package/dist/local-auth/core/generators/auth-module/generated/index.d.ts +65 -4
- package/dist/local-auth/core/generators/auth-module/generated/template-paths.d.ts +1 -1
- package/dist/local-auth/core/generators/auth-module/generated/template-paths.js +1 -1
- package/dist/local-auth/core/generators/auth-module/generated/template-renderers.d.ts +22 -1
- package/dist/local-auth/core/generators/auth-module/generated/template-renderers.js +19 -2
- package/dist/local-auth/core/generators/auth-module/generated/ts-import-providers.d.ts +10 -0
- package/dist/local-auth/core/generators/auth-module/generated/ts-import-providers.js +7 -0
- package/dist/local-auth/core/generators/auth-module/generated/typed-templates.d.ts +42 -4
- package/dist/local-auth/core/generators/auth-module/generated/typed-templates.js +24 -13
- package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.d.ts +4 -0
- package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.js +1 -1
- package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.ts +1 -1
- package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.d.ts +67 -0
- package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.js +140 -0
- package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.ts +191 -0
- package/dist/local-auth/core/generators/auth-module/templates/module/services/user-session.service.js +8 -9
- package/dist/local-auth/core/generators/auth-module/templates/module/services/user-session.service.ts +10 -11
- package/dist/local-auth/core/generators/auth-routes/auth-routes.generator.d.ts +39 -0
- package/dist/local-auth/core/generators/auth-routes/auth-routes.generator.js +38 -5
- package/dist/local-auth/core/generators/auth-routes/generated/index.d.ts +1089 -268
- package/dist/local-auth/core/generators/auth-routes/generated/template-paths.d.ts +3 -0
- package/dist/local-auth/core/generators/auth-routes/generated/template-paths.js +3 -0
- package/dist/local-auth/core/generators/auth-routes/generated/template-renderers.d.ts +49 -0
- package/dist/local-auth/core/generators/auth-routes/generated/template-renderers.js +51 -0
- package/dist/local-auth/core/generators/auth-routes/generated/ts-import-providers.d.ts +1 -0
- package/dist/local-auth/core/generators/auth-routes/generated/ts-import-providers.js +1 -0
- package/dist/local-auth/core/generators/auth-routes/generated/typed-templates.d.ts +918 -283
- package/dist/local-auth/core/generators/auth-routes/generated/typed-templates.js +69 -23
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.d.ts +9 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.js +10 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.ts +11 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.d.ts +7 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.js +155 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.tsx +274 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/forgot-password.js +1 -2
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/forgot-password.tsx +1 -1
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.d.ts +7 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.js +184 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.tsx +312 -0
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login.js +5 -5
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login.tsx +6 -12
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/register.js +4 -4
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/register.tsx +4 -3
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/reset-password.js +1 -2
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/reset-password.tsx +1 -1
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/verify-email.js +1 -2
- package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/verify-email.tsx +1 -1
- package/dist/local-auth/core/generators/react-session/generated/index.d.ts +90 -7
- package/dist/local-auth/core/generators/react-session/generated/template-renderers.d.ts +38 -1
- package/dist/local-auth/core/generators/react-session/generated/ts-import-providers.d.ts +1 -0
- package/dist/local-auth/core/generators/react-session/generated/ts-import-providers.js +1 -0
- package/dist/local-auth/core/generators/react-session/generated/typed-templates.d.ts +102 -12
- package/dist/local-auth/core/generators/react-session/generated/typed-templates.js +5 -2
- package/dist/local-auth/core/generators/react-session/react-session.generator.d.ts +54 -1
- package/dist/local-auth/core/generators/react-session/react-session.generator.js +35 -1
- package/dist/local-auth/core/generators/react-session/templates/src/app/user-session-provider.js +17 -44
- package/dist/local-auth/core/generators/react-session/templates/src/app/user-session-provider.tsx +21 -49
- package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.d.ts +43 -34
- package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.js +96 -80
- package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.ts +148 -82
- package/dist/local-auth/core/generators/seed-initial-user/generated/index.d.ts +0 -2
- package/dist/local-auth/core/generators/seed-initial-user/generated/template-renderers.d.ts +0 -1
- package/dist/local-auth/core/generators/seed-initial-user/generated/typed-templates.d.ts +0 -1
- package/dist/local-auth/core/generators/seed-initial-user/seed-initial-user.generator.d.ts +0 -1
- package/dist/local-auth/core/node.js +30 -12
- package/dist/local-auth/core/schema/migrations.d.ts +3 -0
- package/dist/local-auth/core/schema/migrations.js +36 -0
- package/dist/local-auth/core/schema/models.js +8 -0
- package/dist/local-auth/core/schema/plugin-definition.d.ts +1 -0
- package/dist/local-auth/core/schema/plugin-definition.js +1 -0
- package/dist/local-auth/core/schema/web-app-schema.d.ts +15 -0
- package/dist/local-auth/core/schema/web-app-schema.js +16 -0
- package/dist/local-auth/core/web.js +8 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/index.d.ts +4 -3
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/template-paths.d.ts +1 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/template-paths.js +1 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/ts-import-providers.d.ts +2 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/ts-import-providers.js +2 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/typed-templates.d.ts +4 -4
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/typed-templates.js +13 -13
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/placeholder-auth-hooks.generator.d.ts +1 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/templates/src/hooks/use-session.d.ts +1 -0
- package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/templates/src/hooks/use-session.ts +2 -0
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/index.d.ts +1 -2
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/template-renderers.d.ts +0 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/ts-import-providers.d.ts +1 -0
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/ts-import-providers.js +1 -0
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/typed-templates.d.ts +0 -1
- package/dist/placeholder-auth/core/generators/placeholder-auth-module/placeholder-auth-module.generator.d.ts +0 -1
- package/dist/web/assets/{_virtual_mf-localSharedImportMap___mfe_internal__plugin_mf_2_auth-ChkXxpXe.js → _virtual_mf-localSharedImportMap___mfe_internal__plugin_mf_2_auth__mf_owner__1-DUupKqD4.js} +42 -34
- package/dist/web/assets/{dist-DY7ZXvq4.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib__loadShare__.js-DE4rTqEA.js} +16857 -381
- package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib_mf_1_web__loadShare__.js-37vlYRxk.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib_mf_1_web__loadShare__.js-mszeXpf-.js} +90 -38
- package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_ui_mf_2_components__loadShare__.js-DRSNXPPo.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_ui_mf_2_components__loadShare__.js-CtIleM_e.js} +4095 -2399
- package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_tanstack_mf_1_react_mf_2_router__loadShare__.js-DfiQqvVC.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_tanstack_mf_1_react_mf_2_router__loadShare__.js-BckLhSjF.js} +212 -57
- package/dist/web/assets/auth-DR6QxrAW.js +1 -0
- package/dist/web/assets/{common-iHaemino.js → common-BsyRiQi3.js} +6 -6
- package/dist/web/assets/{common-TDf_PrjX.js → common-CRwNlCMn.js} +10 -10
- package/dist/web/assets/{common-ByxS61u8.js → common-CvqlRZC9.js} +12 -12
- package/dist/web/assets/common-D3atSs7O.js +70 -0
- package/dist/web/assets/common-DuFyXa6l.js +36 -0
- package/dist/web/assets/common-islduJTj.js +43 -0
- package/dist/web/assets/{dist-CrLSslv6.js → dist-DQd1TAJX.js} +273 -132
- package/dist/web/assets/{get-auth-plugin-definition-kDCtXq_6.js → get-auth-plugin-definition-BgWWHl_Y.js} +3 -3
- package/dist/web/assets/{hostInit-Cruek6c6.js → hostInit-DNA4kLRY.js} +32 -5
- package/dist/web/assets/{mf-entry-bootstrap-0-dfed0275.js → mf-entry-bootstrap-0-ea77c09b.js} +2 -1
- package/dist/web/assets/{mf-entry-bootstrap-1-5275674a.js → mf-entry-bootstrap-1-9dee3d8d.js} +3 -2
- package/dist/web/assets/{mf-entry-bootstrap-2-39fb9255.js → mf-entry-bootstrap-2-3179040b.js} +3 -2
- package/dist/web/assets/{mf-entry-bootstrap-3-49e64336.js → mf-entry-bootstrap-3-370d200d.js} +3 -2
- package/dist/web/assets/{models-DSvs_3bA.js → models-BOeSYfRn.js} +4 -5
- package/dist/web/assets/{models-BZmCbizK.js → models-DF6DoXt6.js} +11 -6
- package/dist/web/assets/{plugin-definition-CYj29S3q.js → plugin-definition--k0VAeK3.js} +9 -10
- package/dist/web/assets/plugin-definition-CMwSlxsJ.js +10 -0
- package/dist/web/assets/{styles-yjbHBTlw.js → styles-BQEcQHoR.js} +9 -10
- package/dist/web/assets/{virtualExposes-CbPBmicF.js → virtualExposes-C7fDiAmS.js} +1 -1
- package/dist/web/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__plugin-auth__remoteEntry_js-BZBRyml2.js +747 -0
- package/dist/web/assets/{virtual_mf-exposes___mfe_internal__plugin-auth__remoteEntry_js-B6BXIeF1.js → virtual_mf-exposes___mfe_internal__plugin-auth__remoteEntry_js-6SjVUCs8.js} +13 -13
- package/dist/web/assets/web-8wz0ad-V.js +59 -0
- package/dist/web/assets/{web-CXAHKjIY.js → web-BGixH_gT.js} +27 -27
- package/dist/web/assets/{web-1eTcxMhf.js → web-BxIwkN3O.js} +6 -6
- package/dist/web/assets/{web-VqBA3jxZ.js → web-CQMfABjr.js} +24 -24
- package/dist/web/assets/{web-CDAKPPK9.js → web-CcNpItSu.js} +22 -22
- package/dist/web/assets/web-CypPeiVv.js +148 -0
- package/dist/web/assets/{web-D0MSKfyv.js → web-CzK_la2_.js} +53 -53
- package/dist/web/index.html +5 -5
- package/dist/web/remoteEntry.js +1 -1
- package/package.json +14 -14
- package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.d.ts +0 -38
- package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.js +0 -71
- package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.ts +0 -77
- package/dist/web/assets/_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib__loadShare__.js-CO5Pvo0y.js +0 -384
- package/dist/web/assets/_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare__zod__loadShare__.js-BEZ7A-cz.js +0 -13566
- package/dist/web/assets/auth-BxAE0rgh.js +0 -1
- package/dist/web/assets/common-CKl_XlvH.js +0 -37
- package/dist/web/assets/common-UpVCKZeW.js +0 -41
- package/dist/web/assets/common-crSwCD36.js +0 -37
- package/dist/web/assets/model-utils-C0WDb_Ec.js +0 -1599
- package/dist/web/assets/plugin-definition-DOMmPL2Z.js +0 -11
- package/dist/web/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__plugin-auth__remoteEntry_js-XM6iYVxf.js +0 -259
- package/dist/web/assets/virtual_mf-exposes-ssr___mfe_internal__plugin-auth__remoteEntry_js-DGjg7Brm.js +0 -129
- package/dist/web/assets/web-DbeAaDTV.js +0 -118
- package/dist/web/assets/web-miDovYk_.js +0 -46
- package/dist/web/remoteEntry.ssr.js +0 -43
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { AuthVerification, Prisma } from '%prismaGeneratedImports';
|
|
2
|
+
/**
|
|
3
|
+
* Creates or replaces a short code verification (e.g. an emailed OTP).
|
|
4
|
+
*
|
|
5
|
+
* The identifier is caller-supplied (typically an email) rather than a random
|
|
6
|
+
* selector, so the code cannot be folded into a single token the way a
|
|
7
|
+
* split-token flow does. Only one code may be outstanding per
|
|
8
|
+
* `type`/`identifier` pair, so requesting a new one replaces any existing code
|
|
9
|
+
* and resets the attempt counter.
|
|
10
|
+
*
|
|
11
|
+
* The identifier rather than a user reference is the subject here, since a
|
|
12
|
+
* code may be issued for an address that has no account yet.
|
|
13
|
+
*
|
|
14
|
+
* The returned id identifies this particular issuance, so a caller that binds
|
|
15
|
+
* it to the requester (e.g. in a cookie) can tell one request apart from the
|
|
16
|
+
* next. It is regenerated on every call for that reason: reusing it would let
|
|
17
|
+
* whoever requested an earlier code redeem a later one requested by someone
|
|
18
|
+
* else.
|
|
19
|
+
*
|
|
20
|
+
* @param code - The plaintext code sent to the user; only its hash is stored
|
|
21
|
+
*/
|
|
22
|
+
export declare function createCodeVerification({ type, identifier, code, expiresInSec, }: {
|
|
23
|
+
type: string;
|
|
24
|
+
identifier: string;
|
|
25
|
+
code: string;
|
|
26
|
+
expiresInSec: number;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
id: string;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Validates a short code verification, leaving the record in place so the
|
|
32
|
+
* caller can gather any further input it needs before committing.
|
|
33
|
+
*
|
|
34
|
+
* Security: a short numeric code has far less entropy than a random token, so
|
|
35
|
+
* each code carries its own attempt counter alongside the endpoint rate limits.
|
|
36
|
+
* Every call spends an attempt, including one that matches, and the record is
|
|
37
|
+
* deleted once the code has expired or a wrong guess has spent the last
|
|
38
|
+
* attempt. Pass the returned record to {@link consumeCodeVerification} to
|
|
39
|
+
* complete the flow.
|
|
40
|
+
*
|
|
41
|
+
* The cleanup paths delete by filter rather than by primary key: simultaneous
|
|
42
|
+
* callers can each decide the record should go, and only one of them removes a
|
|
43
|
+
* row.
|
|
44
|
+
*/
|
|
45
|
+
export declare function validateCodeVerification({ type, identifier, code, maxAttempts, }: {
|
|
46
|
+
type: string;
|
|
47
|
+
identifier: string;
|
|
48
|
+
code: string;
|
|
49
|
+
maxAttempts: number;
|
|
50
|
+
}): Promise<AuthVerification | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Consumes a previously validated verification, returning whether this call is
|
|
53
|
+
* the one that claimed it.
|
|
54
|
+
*
|
|
55
|
+
* The conditional delete is the authorization step: concurrent requests
|
|
56
|
+
* carrying the same code race here, and only the request that removes the row
|
|
57
|
+
* may proceed. Reading the row and deleting it in separate statements would
|
|
58
|
+
* let both win.
|
|
59
|
+
*
|
|
60
|
+
* @param client - Transaction client, so consuming the code can be committed
|
|
61
|
+
* together with whatever the code authorized rather than ahead of it
|
|
62
|
+
*/
|
|
63
|
+
export declare function consumeCodeVerification({ id, client, }: {
|
|
64
|
+
id: string;
|
|
65
|
+
client?: Prisma.TransactionClient;
|
|
66
|
+
}): Promise<boolean>;
|
|
67
|
+
//# sourceMappingURL=code-verification.service.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { safeCompare } from '$servicesAuthVerification';
|
|
3
|
+
import { deriveKey } from '%appSecretImports';
|
|
4
|
+
import { prisma } from '%prismaImports';
|
|
5
|
+
import * as crypto from 'node:crypto';
|
|
6
|
+
/**
|
|
7
|
+
* Short code verifications, for flows that email a handful of digits rather
|
|
8
|
+
* than a link.
|
|
9
|
+
*
|
|
10
|
+
* These share the `AuthVerification` table with the split-token flows in
|
|
11
|
+
* {@link ./auth-verification.service.js} but not their security model: the
|
|
12
|
+
* secret is short enough to guess, so it is keyed rather than hashed, carries
|
|
13
|
+
* its own attempt budget, and is addressed by a caller-supplied identifier
|
|
14
|
+
* instead of a random selector.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Derives the stored value for a short code.
|
|
18
|
+
*
|
|
19
|
+
* Short codes occupy a keyspace small enough to invert a plain digest by
|
|
20
|
+
* exhaustive search, so they are keyed with the server secret rather than
|
|
21
|
+
* hashed: an attacker holding only the database cannot recover them. The type
|
|
22
|
+
* and identifier are mixed in so a stored value is valid solely for the flow
|
|
23
|
+
* and address it was issued for.
|
|
24
|
+
*/
|
|
25
|
+
function hashCode({ type, identifier, code, }) {
|
|
26
|
+
return crypto
|
|
27
|
+
.createHmac('sha256', deriveKey('auth:code-verification:v1'))
|
|
28
|
+
.update(`${type}:${identifier}:${code}`)
|
|
29
|
+
.digest('hex');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates or replaces a short code verification (e.g. an emailed OTP).
|
|
33
|
+
*
|
|
34
|
+
* The identifier is caller-supplied (typically an email) rather than a random
|
|
35
|
+
* selector, so the code cannot be folded into a single token the way a
|
|
36
|
+
* split-token flow does. Only one code may be outstanding per
|
|
37
|
+
* `type`/`identifier` pair, so requesting a new one replaces any existing code
|
|
38
|
+
* and resets the attempt counter.
|
|
39
|
+
*
|
|
40
|
+
* The identifier rather than a user reference is the subject here, since a
|
|
41
|
+
* code may be issued for an address that has no account yet.
|
|
42
|
+
*
|
|
43
|
+
* The returned id identifies this particular issuance, so a caller that binds
|
|
44
|
+
* it to the requester (e.g. in a cookie) can tell one request apart from the
|
|
45
|
+
* next. It is regenerated on every call for that reason: reusing it would let
|
|
46
|
+
* whoever requested an earlier code redeem a later one requested by someone
|
|
47
|
+
* else.
|
|
48
|
+
*
|
|
49
|
+
* @param code - The plaintext code sent to the user; only its hash is stored
|
|
50
|
+
*/
|
|
51
|
+
export async function createCodeVerification({ type, identifier, code, expiresInSec, }) {
|
|
52
|
+
const value = hashCode({ type, identifier, code });
|
|
53
|
+
const expiresAt = new Date(Date.now() + expiresInSec * 1000);
|
|
54
|
+
const id = crypto.randomUUID();
|
|
55
|
+
await prisma.authVerification.upsert({
|
|
56
|
+
where: { type_identifier: { type, identifier } },
|
|
57
|
+
create: {
|
|
58
|
+
id,
|
|
59
|
+
type,
|
|
60
|
+
identifier,
|
|
61
|
+
value,
|
|
62
|
+
expiresAt,
|
|
63
|
+
},
|
|
64
|
+
// Resetting `attempts` is what gives the replacement code a fresh budget;
|
|
65
|
+
// without it a reissued code would inherit the old code's failed guesses.
|
|
66
|
+
update: {
|
|
67
|
+
id,
|
|
68
|
+
value,
|
|
69
|
+
attempts: 0,
|
|
70
|
+
expiresAt,
|
|
71
|
+
},
|
|
72
|
+
select: { id: true },
|
|
73
|
+
});
|
|
74
|
+
return { id };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validates a short code verification, leaving the record in place so the
|
|
78
|
+
* caller can gather any further input it needs before committing.
|
|
79
|
+
*
|
|
80
|
+
* Security: a short numeric code has far less entropy than a random token, so
|
|
81
|
+
* each code carries its own attempt counter alongside the endpoint rate limits.
|
|
82
|
+
* Every call spends an attempt, including one that matches, and the record is
|
|
83
|
+
* deleted once the code has expired or a wrong guess has spent the last
|
|
84
|
+
* attempt. Pass the returned record to {@link consumeCodeVerification} to
|
|
85
|
+
* complete the flow.
|
|
86
|
+
*
|
|
87
|
+
* The cleanup paths delete by filter rather than by primary key: simultaneous
|
|
88
|
+
* callers can each decide the record should go, and only one of them removes a
|
|
89
|
+
* row.
|
|
90
|
+
*/
|
|
91
|
+
export async function validateCodeVerification({ type, identifier, code, maxAttempts, }) {
|
|
92
|
+
const record = await prisma.authVerification.findUnique({
|
|
93
|
+
where: { type_identifier: { type, identifier } },
|
|
94
|
+
});
|
|
95
|
+
if (!record) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (record.expiresAt < new Date()) {
|
|
99
|
+
await prisma.authVerification.deleteMany({ where: { id: record.id } });
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// Simultaneous guesses serialize on this statement, so at most `maxAttempts`
|
|
103
|
+
// of them reach the comparison below.
|
|
104
|
+
const [claimed] = await prisma.authVerification.updateManyAndReturn({
|
|
105
|
+
where: { id: record.id, attempts: { lt: maxAttempts } },
|
|
106
|
+
data: { attempts: { increment: 1 } },
|
|
107
|
+
});
|
|
108
|
+
// A spent budget is not this caller's to clean up: the guess that spent it
|
|
109
|
+
// discards the record below, and a correct guess that spent it may still be
|
|
110
|
+
// holding the record for {@link consumeCodeVerification}.
|
|
111
|
+
if (!claimed) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
if (safeCompare(claimed.value, hashCode({ type, identifier, code }))) {
|
|
115
|
+
return claimed;
|
|
116
|
+
}
|
|
117
|
+
if (claimed.attempts >= maxAttempts) {
|
|
118
|
+
await prisma.authVerification.deleteMany({ where: { id: record.id } });
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Consumes a previously validated verification, returning whether this call is
|
|
124
|
+
* the one that claimed it.
|
|
125
|
+
*
|
|
126
|
+
* The conditional delete is the authorization step: concurrent requests
|
|
127
|
+
* carrying the same code race here, and only the request that removes the row
|
|
128
|
+
* may proceed. Reading the row and deleting it in separate statements would
|
|
129
|
+
* let both win.
|
|
130
|
+
*
|
|
131
|
+
* @param client - Transaction client, so consuming the code can be committed
|
|
132
|
+
* together with whatever the code authorized rather than ahead of it
|
|
133
|
+
*/
|
|
134
|
+
export async function consumeCodeVerification({ id, client = prisma, }) {
|
|
135
|
+
const { count } = await client.authVerification.deleteMany({
|
|
136
|
+
where: { id },
|
|
137
|
+
});
|
|
138
|
+
return count === 1;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=code-verification.service.js.map
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
import type { AuthVerification, Prisma } from '%prismaGeneratedImports';
|
|
4
|
+
|
|
5
|
+
import { safeCompare } from '$servicesAuthVerification';
|
|
6
|
+
import { deriveKey } from '%appSecretImports';
|
|
7
|
+
import { prisma } from '%prismaImports';
|
|
8
|
+
import * as crypto from 'node:crypto';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Short code verifications, for flows that email a handful of digits rather
|
|
12
|
+
* than a link.
|
|
13
|
+
*
|
|
14
|
+
* These share the `AuthVerification` table with the split-token flows in
|
|
15
|
+
* {@link ./auth-verification.service.js} but not their security model: the
|
|
16
|
+
* secret is short enough to guess, so it is keyed rather than hashed, carries
|
|
17
|
+
* its own attempt budget, and is addressed by a caller-supplied identifier
|
|
18
|
+
* instead of a random selector.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Derives the stored value for a short code.
|
|
23
|
+
*
|
|
24
|
+
* Short codes occupy a keyspace small enough to invert a plain digest by
|
|
25
|
+
* exhaustive search, so they are keyed with the server secret rather than
|
|
26
|
+
* hashed: an attacker holding only the database cannot recover them. The type
|
|
27
|
+
* and identifier are mixed in so a stored value is valid solely for the flow
|
|
28
|
+
* and address it was issued for.
|
|
29
|
+
*/
|
|
30
|
+
function hashCode({
|
|
31
|
+
type,
|
|
32
|
+
identifier,
|
|
33
|
+
code,
|
|
34
|
+
}: {
|
|
35
|
+
type: string;
|
|
36
|
+
identifier: string;
|
|
37
|
+
code: string;
|
|
38
|
+
}): string {
|
|
39
|
+
return crypto
|
|
40
|
+
.createHmac('sha256', deriveKey('auth:code-verification:v1'))
|
|
41
|
+
.update(`${type}:${identifier}:${code}`)
|
|
42
|
+
.digest('hex');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates or replaces a short code verification (e.g. an emailed OTP).
|
|
47
|
+
*
|
|
48
|
+
* The identifier is caller-supplied (typically an email) rather than a random
|
|
49
|
+
* selector, so the code cannot be folded into a single token the way a
|
|
50
|
+
* split-token flow does. Only one code may be outstanding per
|
|
51
|
+
* `type`/`identifier` pair, so requesting a new one replaces any existing code
|
|
52
|
+
* and resets the attempt counter.
|
|
53
|
+
*
|
|
54
|
+
* The identifier rather than a user reference is the subject here, since a
|
|
55
|
+
* code may be issued for an address that has no account yet.
|
|
56
|
+
*
|
|
57
|
+
* The returned id identifies this particular issuance, so a caller that binds
|
|
58
|
+
* it to the requester (e.g. in a cookie) can tell one request apart from the
|
|
59
|
+
* next. It is regenerated on every call for that reason: reusing it would let
|
|
60
|
+
* whoever requested an earlier code redeem a later one requested by someone
|
|
61
|
+
* else.
|
|
62
|
+
*
|
|
63
|
+
* @param code - The plaintext code sent to the user; only its hash is stored
|
|
64
|
+
*/
|
|
65
|
+
export async function createCodeVerification({
|
|
66
|
+
type,
|
|
67
|
+
identifier,
|
|
68
|
+
code,
|
|
69
|
+
expiresInSec,
|
|
70
|
+
}: {
|
|
71
|
+
type: string;
|
|
72
|
+
identifier: string;
|
|
73
|
+
code: string;
|
|
74
|
+
expiresInSec: number;
|
|
75
|
+
}): Promise<{ id: string }> {
|
|
76
|
+
const value = hashCode({ type, identifier, code });
|
|
77
|
+
const expiresAt = new Date(Date.now() + expiresInSec * 1000);
|
|
78
|
+
const id = crypto.randomUUID();
|
|
79
|
+
|
|
80
|
+
await prisma.authVerification.upsert({
|
|
81
|
+
where: { type_identifier: { type, identifier } },
|
|
82
|
+
create: {
|
|
83
|
+
id,
|
|
84
|
+
type,
|
|
85
|
+
identifier,
|
|
86
|
+
value,
|
|
87
|
+
expiresAt,
|
|
88
|
+
},
|
|
89
|
+
// Resetting `attempts` is what gives the replacement code a fresh budget;
|
|
90
|
+
// without it a reissued code would inherit the old code's failed guesses.
|
|
91
|
+
update: {
|
|
92
|
+
id,
|
|
93
|
+
value,
|
|
94
|
+
attempts: 0,
|
|
95
|
+
expiresAt,
|
|
96
|
+
},
|
|
97
|
+
select: { id: true },
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return { id };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Validates a short code verification, leaving the record in place so the
|
|
105
|
+
* caller can gather any further input it needs before committing.
|
|
106
|
+
*
|
|
107
|
+
* Security: a short numeric code has far less entropy than a random token, so
|
|
108
|
+
* each code carries its own attempt counter alongside the endpoint rate limits.
|
|
109
|
+
* Every call spends an attempt, including one that matches, and the record is
|
|
110
|
+
* deleted once the code has expired or a wrong guess has spent the last
|
|
111
|
+
* attempt. Pass the returned record to {@link consumeCodeVerification} to
|
|
112
|
+
* complete the flow.
|
|
113
|
+
*
|
|
114
|
+
* The cleanup paths delete by filter rather than by primary key: simultaneous
|
|
115
|
+
* callers can each decide the record should go, and only one of them removes a
|
|
116
|
+
* row.
|
|
117
|
+
*/
|
|
118
|
+
export async function validateCodeVerification({
|
|
119
|
+
type,
|
|
120
|
+
identifier,
|
|
121
|
+
code,
|
|
122
|
+
maxAttempts,
|
|
123
|
+
}: {
|
|
124
|
+
type: string;
|
|
125
|
+
identifier: string;
|
|
126
|
+
code: string;
|
|
127
|
+
maxAttempts: number;
|
|
128
|
+
}): Promise<AuthVerification | null> {
|
|
129
|
+
const record = await prisma.authVerification.findUnique({
|
|
130
|
+
where: { type_identifier: { type, identifier } },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (!record) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (record.expiresAt < new Date()) {
|
|
138
|
+
await prisma.authVerification.deleteMany({ where: { id: record.id } });
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Simultaneous guesses serialize on this statement, so at most `maxAttempts`
|
|
143
|
+
// of them reach the comparison below.
|
|
144
|
+
const [claimed] = await prisma.authVerification.updateManyAndReturn({
|
|
145
|
+
where: { id: record.id, attempts: { lt: maxAttempts } },
|
|
146
|
+
data: { attempts: { increment: 1 } },
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// A spent budget is not this caller's to clean up: the guess that spent it
|
|
150
|
+
// discards the record below, and a correct guess that spent it may still be
|
|
151
|
+
// holding the record for {@link consumeCodeVerification}.
|
|
152
|
+
if (!claimed) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (safeCompare(claimed.value, hashCode({ type, identifier, code }))) {
|
|
157
|
+
return claimed;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (claimed.attempts >= maxAttempts) {
|
|
161
|
+
await prisma.authVerification.deleteMany({ where: { id: record.id } });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Consumes a previously validated verification, returning whether this call is
|
|
169
|
+
* the one that claimed it.
|
|
170
|
+
*
|
|
171
|
+
* The conditional delete is the authorization step: concurrent requests
|
|
172
|
+
* carrying the same code race here, and only the request that removes the row
|
|
173
|
+
* may proceed. Reading the row and deleting it in separate statements would
|
|
174
|
+
* let both win.
|
|
175
|
+
*
|
|
176
|
+
* @param client - Transaction client, so consuming the code can be committed
|
|
177
|
+
* together with whatever the code authorized rather than ahead of it
|
|
178
|
+
*/
|
|
179
|
+
export async function consumeCodeVerification({
|
|
180
|
+
id,
|
|
181
|
+
client = prisma,
|
|
182
|
+
}: {
|
|
183
|
+
id: string;
|
|
184
|
+
client?: Prisma.TransactionClient;
|
|
185
|
+
}): Promise<boolean> {
|
|
186
|
+
const { count } = await client.authVerification.deleteMany({
|
|
187
|
+
where: { id },
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return count === 1;
|
|
191
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import { signObject, unsignObject } from '$cookieSigner';
|
|
3
2
|
import { getUserSessionCookieName } from '$sessionCookie';
|
|
4
3
|
import { USER_SESSION_DURATION_SEC, USER_SESSION_MAX_LIFETIME_SEC, USER_SESSION_RENEWAL_THRESHOLD_SEC, } from '$userSessionConstants';
|
|
5
4
|
import { verifyRequestOrigin } from '$verifyRequestOrigin';
|
|
5
|
+
import { createSigner } from '%appSecretImports';
|
|
6
|
+
import { getWebOrigins } from '%appUrlsImports';
|
|
6
7
|
import { InvalidSessionError } from '%authContextImports';
|
|
7
8
|
import { DEFAULT_USER_ROLES } from '%authRolesImports';
|
|
8
|
-
import {
|
|
9
|
+
import { isDevelopment } from '%configServiceImports';
|
|
9
10
|
import { ForbiddenError } from '%errorHandlerServiceImports';
|
|
10
11
|
import { prisma } from '%prismaImports';
|
|
11
12
|
import { randomBytes } from 'node:crypto';
|
|
13
|
+
const sessionCookieSigner = createSigner('auth:session:v1');
|
|
12
14
|
function getCookieOptions() {
|
|
13
15
|
return {
|
|
14
16
|
httpOnly: true,
|
|
@@ -85,7 +87,7 @@ export class CookieUserSessionService {
|
|
|
85
87
|
...user.roles.map((role) => role.role),
|
|
86
88
|
];
|
|
87
89
|
const cookieName = getUserSessionCookieName(context.reqInfo.headers);
|
|
88
|
-
const cookieValue =
|
|
90
|
+
const cookieValue = sessionCookieSigner.sign({ token });
|
|
89
91
|
context.cookieStore.set(cookieName, cookieValue, getCookieOptions());
|
|
90
92
|
return { userId, expiresAt, roles };
|
|
91
93
|
}
|
|
@@ -122,17 +124,14 @@ export class CookieUserSessionService {
|
|
|
122
124
|
if ((req.method !== 'GET' ||
|
|
123
125
|
req.headers.upgrade?.toLowerCase() === 'websocket') &&
|
|
124
126
|
req.method !== 'HEAD' &&
|
|
125
|
-
!verifyRequestOrigin(req, [req.host, ...
|
|
127
|
+
!verifyRequestOrigin(req, [req.host, ...getWebOrigins()])) {
|
|
126
128
|
throw new ForbiddenError('Invalid Origin header');
|
|
127
129
|
}
|
|
128
130
|
try {
|
|
129
|
-
|
|
130
|
-
const sessionCookieResult = unsignObject(sessionCookieValue, getConfig().AUTH_SECRET);
|
|
131
|
+
const sessionCookieResult = sessionCookieSigner.verify(sessionCookieValue);
|
|
131
132
|
if (!sessionCookieResult)
|
|
132
133
|
throw new InvalidSessionError();
|
|
133
134
|
const { token } = sessionCookieResult;
|
|
134
|
-
if (typeof token !== 'string')
|
|
135
|
-
throw new InvalidSessionError();
|
|
136
135
|
// Fetch and validate user session
|
|
137
136
|
const userSession = await TPL_PRISMA_USER_SESSION.findUnique({
|
|
138
137
|
where: { token },
|
|
@@ -152,7 +151,7 @@ export class CookieUserSessionService {
|
|
|
152
151
|
expiresAt: sessionExpiryResult.newExpiry,
|
|
153
152
|
},
|
|
154
153
|
});
|
|
155
|
-
const newSignedCookie =
|
|
154
|
+
const newSignedCookie = sessionCookieSigner.sign({ token });
|
|
156
155
|
reply.setCookie(cookieName, newSignedCookie, getCookieOptions());
|
|
157
156
|
}
|
|
158
157
|
const { user } = userSession;
|
|
@@ -10,7 +10,6 @@ import type {
|
|
|
10
10
|
import type { CookieSerializeOptions } from '@fastify/cookie';
|
|
11
11
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
|
12
12
|
|
|
13
|
-
import { signObject, unsignObject } from '$cookieSigner';
|
|
14
13
|
import { getUserSessionCookieName } from '$sessionCookie';
|
|
15
14
|
import {
|
|
16
15
|
USER_SESSION_DURATION_SEC,
|
|
@@ -18,9 +17,11 @@ import {
|
|
|
18
17
|
USER_SESSION_RENEWAL_THRESHOLD_SEC,
|
|
19
18
|
} from '$userSessionConstants';
|
|
20
19
|
import { verifyRequestOrigin } from '$verifyRequestOrigin';
|
|
20
|
+
import { createSigner } from '%appSecretImports';
|
|
21
|
+
import { getWebOrigins } from '%appUrlsImports';
|
|
21
22
|
import { InvalidSessionError } from '%authContextImports';
|
|
22
23
|
import { DEFAULT_USER_ROLES } from '%authRolesImports';
|
|
23
|
-
import {
|
|
24
|
+
import { isDevelopment } from '%configServiceImports';
|
|
24
25
|
import { ForbiddenError } from '%errorHandlerServiceImports';
|
|
25
26
|
import { prisma } from '%prismaImports';
|
|
26
27
|
import { randomBytes } from 'node:crypto';
|
|
@@ -30,6 +31,8 @@ interface SessionCookieValue {
|
|
|
30
31
|
token: string;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
const sessionCookieSigner = createSigner<SessionCookieValue>('auth:session:v1');
|
|
35
|
+
|
|
33
36
|
function getCookieOptions(): CookieSerializeOptions {
|
|
34
37
|
return {
|
|
35
38
|
httpOnly: true,
|
|
@@ -131,7 +134,7 @@ export class CookieUserSessionService implements UserSessionService {
|
|
|
131
134
|
];
|
|
132
135
|
|
|
133
136
|
const cookieName = getUserSessionCookieName(context.reqInfo.headers);
|
|
134
|
-
const cookieValue =
|
|
137
|
+
const cookieValue = sessionCookieSigner.sign({ token });
|
|
135
138
|
|
|
136
139
|
context.cookieStore.set(cookieName, cookieValue, getCookieOptions());
|
|
137
140
|
|
|
@@ -182,20 +185,16 @@ export class CookieUserSessionService implements UserSessionService {
|
|
|
182
185
|
(req.method !== 'GET' ||
|
|
183
186
|
req.headers.upgrade?.toLowerCase() === 'websocket') &&
|
|
184
187
|
req.method !== 'HEAD' &&
|
|
185
|
-
!verifyRequestOrigin(req, [req.host, ...
|
|
188
|
+
!verifyRequestOrigin(req, [req.host, ...getWebOrigins()])
|
|
186
189
|
) {
|
|
187
190
|
throw new ForbiddenError('Invalid Origin header');
|
|
188
191
|
}
|
|
189
192
|
try {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
sessionCookieValue,
|
|
193
|
-
getConfig().AUTH_SECRET,
|
|
194
|
-
) as SessionCookieValue | undefined;
|
|
193
|
+
const sessionCookieResult =
|
|
194
|
+
sessionCookieSigner.verify(sessionCookieValue);
|
|
195
195
|
if (!sessionCookieResult) throw new InvalidSessionError();
|
|
196
196
|
|
|
197
197
|
const { token } = sessionCookieResult;
|
|
198
|
-
if (typeof token !== 'string') throw new InvalidSessionError();
|
|
199
198
|
|
|
200
199
|
// Fetch and validate user session
|
|
201
200
|
const userSession = await TPL_PRISMA_USER_SESSION.findUnique({
|
|
@@ -220,7 +219,7 @@ export class CookieUserSessionService implements UserSessionService {
|
|
|
220
219
|
expiresAt: sessionExpiryResult.newExpiry,
|
|
221
220
|
},
|
|
222
221
|
});
|
|
223
|
-
const newSignedCookie =
|
|
222
|
+
const newSignedCookie = sessionCookieSigner.sign({ token });
|
|
224
223
|
reply.setCookie(cookieName, newSignedCookie, getCookieOptions());
|
|
225
224
|
}
|
|
226
225
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const authRoutesGenerator: import("@baseplate-dev/sync").GeneratorBundleCreator<{
|
|
5
5
|
requireNameOnRegistration: boolean;
|
|
6
|
+
emailOtp?: boolean | undefined;
|
|
7
|
+
disableRegistration?: boolean | undefined;
|
|
6
8
|
}, {
|
|
7
9
|
paths: import("@baseplate-dev/sync").GeneratorTask<{
|
|
8
10
|
authCoreAuthRoutesPaths: import("@baseplate-dev/sync").ProviderExport<import("./generated/template-paths.js").AuthCoreAuthRoutesPaths>;
|
|
@@ -31,6 +33,7 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
31
33
|
isTypeOnly: true;
|
|
32
34
|
};
|
|
33
35
|
Alert: {};
|
|
36
|
+
AlertAction: {};
|
|
34
37
|
AlertDescription: {};
|
|
35
38
|
AlertTitle: {};
|
|
36
39
|
Autocomplete: {};
|
|
@@ -60,6 +63,7 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
60
63
|
buttonVariants: {};
|
|
61
64
|
Calendar: {};
|
|
62
65
|
Card: {};
|
|
66
|
+
CardAction: {};
|
|
63
67
|
CardContent: {};
|
|
64
68
|
CardDescription: {};
|
|
65
69
|
CardFooter: {};
|
|
@@ -144,6 +148,12 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
144
148
|
InputGroupInput: {};
|
|
145
149
|
InputGroupText: {};
|
|
146
150
|
InputGroupTextarea: {};
|
|
151
|
+
InputOtp: {};
|
|
152
|
+
InputOtpField: {};
|
|
153
|
+
InputOtpFieldController: {};
|
|
154
|
+
InputOtpGroup: {};
|
|
155
|
+
InputOtpSeparator: {};
|
|
156
|
+
InputOtpSlot: {};
|
|
147
157
|
inputVariants: {};
|
|
148
158
|
Item: {};
|
|
149
159
|
ItemActions: {};
|
|
@@ -180,6 +190,10 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
180
190
|
NotFoundCard: {};
|
|
181
191
|
NumberField: {};
|
|
182
192
|
NumberFieldController: {};
|
|
193
|
+
PageHeader: {};
|
|
194
|
+
PageHeaderActions: {};
|
|
195
|
+
PageHeaderDescription: {};
|
|
196
|
+
PageHeaderTitle: {};
|
|
183
197
|
Popover: {};
|
|
184
198
|
PopoverContent: {};
|
|
185
199
|
PopoverTrigger: {};
|
|
@@ -189,6 +203,11 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
189
203
|
isTypeOnly: true;
|
|
190
204
|
};
|
|
191
205
|
ScrollArea: {};
|
|
206
|
+
Section: {};
|
|
207
|
+
SectionActions: {};
|
|
208
|
+
SectionDescription: {};
|
|
209
|
+
SectionHeader: {};
|
|
210
|
+
SectionTitle: {};
|
|
192
211
|
Select: {};
|
|
193
212
|
SelectField: {};
|
|
194
213
|
SelectFieldController: {};
|
|
@@ -244,7 +263,27 @@ export declare const authRoutesGenerator: import("@baseplate-dev/sync").Generato
|
|
|
244
263
|
Textarea: {};
|
|
245
264
|
TextareaField: {};
|
|
246
265
|
TextareaFieldController: {};
|
|
266
|
+
Toast: {};
|
|
267
|
+
toast: {};
|
|
268
|
+
ToastAction: {};
|
|
269
|
+
ToastClose: {};
|
|
270
|
+
ToastContent: {};
|
|
271
|
+
ToastDescription: {};
|
|
247
272
|
Toaster: {};
|
|
273
|
+
toastManager: {};
|
|
274
|
+
ToastOptions: {
|
|
275
|
+
isTypeOnly: true;
|
|
276
|
+
};
|
|
277
|
+
ToastPortal: {};
|
|
278
|
+
ToastProvider: {};
|
|
279
|
+
ToastTitle: {};
|
|
280
|
+
ToastType: {
|
|
281
|
+
isTypeOnly: true;
|
|
282
|
+
};
|
|
283
|
+
ToastUpdateOptions: {
|
|
284
|
+
isTypeOnly: true;
|
|
285
|
+
};
|
|
286
|
+
ToastViewport: {};
|
|
248
287
|
Tooltip: {};
|
|
249
288
|
TooltipContent: {};
|
|
250
289
|
TooltipProvider: {};
|
|
@@ -4,6 +4,8 @@ import { z } from 'zod';
|
|
|
4
4
|
import { AUTH_CORE_AUTH_ROUTES_GENERATED as GENERATED_TEMPLATES } from './generated/index.js';
|
|
5
5
|
const descriptorSchema = z.object({
|
|
6
6
|
requireNameOnRegistration: z.boolean(),
|
|
7
|
+
emailOtp: z.boolean().default(false),
|
|
8
|
+
disableRegistration: z.boolean().default(false),
|
|
7
9
|
});
|
|
8
10
|
/**
|
|
9
11
|
* Generator for auth routes for logging in and registering
|
|
@@ -12,7 +14,7 @@ export const authRoutesGenerator = createGenerator({
|
|
|
12
14
|
name: 'auth/core/auth-routes',
|
|
13
15
|
generatorFileUrl: import.meta.url,
|
|
14
16
|
descriptorSchema,
|
|
15
|
-
buildTasks: ({ requireNameOnRegistration }) => ({
|
|
17
|
+
buildTasks: ({ requireNameOnRegistration, emailOtp, disableRegistration, }) => ({
|
|
16
18
|
paths: GENERATED_TEMPLATES.paths.task,
|
|
17
19
|
renderers: GENERATED_TEMPLATES.renderers.task,
|
|
18
20
|
main: createGeneratorTask({
|
|
@@ -39,7 +41,39 @@ export const authRoutesGenerator = createGenerator({
|
|
|
39
41
|
build: async (builder) => {
|
|
40
42
|
await builder.apply(renderers.mainGroup.render({
|
|
41
43
|
variables: {
|
|
42
|
-
|
|
44
|
+
login: {
|
|
45
|
+
TPL_OTP_LOGIN_LINK: emailOtp
|
|
46
|
+
? `<Link
|
|
47
|
+
to="/auth/login-otp"
|
|
48
|
+
search={{ return_to }}
|
|
49
|
+
className="text-muted-foreground underline-offset-4 hover:underline"
|
|
50
|
+
>
|
|
51
|
+
Sign in with a code instead
|
|
52
|
+
</Link>`
|
|
53
|
+
: '',
|
|
54
|
+
TPL_REGISTER_LINK: disableRegistration
|
|
55
|
+
? ''
|
|
56
|
+
: `<div>
|
|
57
|
+
Don't have an account?{' '}
|
|
58
|
+
<Link
|
|
59
|
+
to="/auth/register"
|
|
60
|
+
className="underline underline-offset-4"
|
|
61
|
+
>
|
|
62
|
+
Sign up
|
|
63
|
+
</Link>
|
|
64
|
+
</div>`,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}));
|
|
68
|
+
await builder.apply(renderers.verifyEmail.render({}));
|
|
69
|
+
await builder.apply(renderers.acceptInvite.render({}));
|
|
70
|
+
if (emailOtp) {
|
|
71
|
+
await builder.apply(renderers.otpConstants.render({}));
|
|
72
|
+
await builder.apply(renderers.loginOtp.render({}));
|
|
73
|
+
}
|
|
74
|
+
if (!disableRegistration) {
|
|
75
|
+
await builder.apply(renderers.register.render({
|
|
76
|
+
variables: {
|
|
43
77
|
TPL_REGISTER_SCHEMA: registerSchema,
|
|
44
78
|
TPL_REGISTER_INPUT: registerInput,
|
|
45
79
|
TPL_NAME_FORM_CONTROL: requireNameOnRegistration
|
|
@@ -53,9 +87,8 @@ export const authRoutesGenerator = createGenerator({
|
|
|
53
87
|
/>`
|
|
54
88
|
: '',
|
|
55
89
|
},
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
await builder.apply(renderers.verifyEmail.render({}));
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
59
92
|
},
|
|
60
93
|
};
|
|
61
94
|
},
|