@antelopejs/interface-dms 0.10.4 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/README.md +21 -10
- package/dist/attachments.d.ts +15 -2
- package/dist/attachments.js +14 -1
- package/dist/attachments.js.map +1 -1
- package/dist/auth/db/models/sessions.model.d.ts +7 -5
- package/dist/auth/db/models/sessions.model.js +2 -9
- package/dist/auth/db/models/sessions.model.js.map +1 -1
- package/dist/auth/db/models/userExternalIdentities.model.d.ts +7 -5
- package/dist/auth/db/models/users.model.d.ts +7 -5
- package/dist/auth/db/tables/users.table.d.ts +2 -2
- package/dist/auth/db/tables/users.table.js.map +1 -1
- package/dist/auth/index.d.ts +4 -4
- package/dist/auth/internal/jwt-auth-decorator.d.ts +1 -1
- package/dist/auth/internal/jwt-auth-decorator.js +6 -3
- package/dist/auth/internal/jwt-auth-decorator.js.map +1 -1
- package/dist/auth/internal/request-authenticators.d.ts +12 -0
- package/dist/auth/internal/request-authenticators.js +53 -10
- package/dist/auth/internal/request-authenticators.js.map +1 -1
- package/dist/base/activity-feed.d.ts +34 -32
- package/dist/base/activity-feed.js +2 -0
- package/dist/base/activity-feed.js.map +1 -1
- package/dist/base/banner.d.ts +12 -10
- package/dist/base/banner.js +2 -0
- package/dist/base/banner.js.map +1 -1
- package/dist/base/block-registry/internal/describe.js +4 -12
- package/dist/base/block-registry/internal/describe.js.map +1 -1
- package/dist/base/block-registry/internal/ui.js +1 -1
- package/dist/base/block-registry/internal/ui.js.map +1 -1
- package/dist/base/card.d.ts +11 -9
- package/dist/base/card.js +2 -0
- package/dist/base/card.js.map +1 -1
- package/dist/base/chart-card.d.ts +4 -2
- package/dist/base/chart-card.js +2 -0
- package/dist/base/chart-card.js.map +1 -1
- package/dist/base/chart-schemas.d.ts +148 -148
- package/dist/base/chart.d.ts +65 -0
- package/dist/base/chart.js +65 -0
- package/dist/base/chart.js.map +1 -1
- package/dist/base/code-block.d.ts +5 -3
- package/dist/base/code-block.js +2 -0
- package/dist/base/code-block.js.map +1 -1
- package/dist/base/custom.d.ts +5 -0
- package/dist/base/custom.js +5 -0
- package/dist/base/custom.js.map +1 -1
- package/dist/base/data-types/default/address.d.ts +5 -0
- package/dist/base/data-types/default/address.js +5 -0
- package/dist/base/data-types/default/address.js.map +1 -1
- package/dist/base/data-types/default/choices.d.ts +20 -0
- package/dist/base/data-types/default/choices.js +20 -0
- package/dist/base/data-types/default/choices.js.map +1 -1
- package/dist/base/data-types/default/files.d.ts +22 -5
- package/dist/base/data-types/default/files.js +20 -0
- package/dist/base/data-types/default/files.js.map +1 -1
- package/dist/base/data-types/default/numbers.d.ts +15 -0
- package/dist/base/data-types/default/numbers.js +25 -9
- package/dist/base/data-types/default/numbers.js.map +1 -1
- package/dist/base/data-types/default/relations.d.ts +10 -2
- package/dist/base/data-types/default/relations.js +9 -6
- package/dist/base/data-types/default/relations.js.map +1 -1
- package/dist/base/data-types/default/strings.d.ts +25 -0
- package/dist/base/data-types/default/strings.js +25 -0
- package/dist/base/data-types/default/strings.js.map +1 -1
- package/dist/base/data-types/default-types.d.ts +1 -1
- package/dist/base/data-types/field-types.d.ts +10 -0
- package/dist/base/data-types/field-types.js +10 -0
- package/dist/base/data-types/field-types.js.map +1 -1
- package/dist/base/data-types/internal/relation-endpoints.js +1 -0
- package/dist/base/data-types/internal/relation-endpoints.js.map +1 -1
- package/dist/base/data-types/status-type.d.ts +5 -0
- package/dist/base/data-types/status-type.js +5 -0
- package/dist/base/data-types/status-type.js.map +1 -1
- package/dist/base/display.d.ts +6 -6
- package/dist/base/empty-state.d.ts +15 -13
- package/dist/base/empty-state.js +2 -0
- package/dist/base/empty-state.js.map +1 -1
- package/dist/base/form-block-schema.d.ts +50 -50
- package/dist/base/form-schema.d.ts +2 -0
- package/dist/base/form-schema.js +2 -0
- package/dist/base/form-schema.js.map +1 -1
- package/dist/base/grid.d.ts +4 -0
- package/dist/base/grid.js +4 -0
- package/dist/base/grid.js.map +1 -1
- package/dist/base/guard.d.ts +30 -28
- package/dist/base/guard.js +2 -0
- package/dist/base/guard.js.map +1 -1
- package/dist/base/helpers/archive-mode-helpers.d.ts +1 -1
- package/dist/base/helpers/file-refs.js +15 -15
- package/dist/base/helpers/file-refs.js.map +1 -1
- package/dist/base/internal/form-schema-validation.js +7 -1
- package/dist/base/internal/form-schema-validation.js.map +1 -1
- package/dist/base/internal/realtime-topics.js.map +1 -1
- package/dist/base/internal/searchable.d.ts +2 -1
- package/dist/base/internal/searchable.js +1 -3
- package/dist/base/internal/searchable.js.map +1 -1
- package/dist/base/key-value-list.d.ts +21 -19
- package/dist/base/key-value-list.js +2 -0
- package/dist/base/key-value-list.js.map +1 -1
- package/dist/base/kpi-card.d.ts +4 -2
- package/dist/base/kpi-card.js +2 -0
- package/dist/base/kpi-card.js.map +1 -1
- package/dist/base/live-toggle.d.ts +2 -0
- package/dist/base/live-toggle.js +2 -0
- package/dist/base/live-toggle.js.map +1 -1
- package/dist/base/meter.d.ts +23 -21
- package/dist/base/meter.js +2 -0
- package/dist/base/meter.js.map +1 -1
- package/dist/base/nav-card-grid.d.ts +24 -19
- package/dist/base/nav-card-grid.js +5 -0
- package/dist/base/nav-card-grid.js.map +1 -1
- package/dist/base/page-toolbar.d.ts +2 -0
- package/dist/base/page-toolbar.js +2 -0
- package/dist/base/page-toolbar.js.map +1 -1
- package/dist/base/period-selector.d.ts +3 -1
- package/dist/base/period-selector.js +2 -0
- package/dist/base/period-selector.js.map +1 -1
- package/dist/base/placeholder.d.ts +2 -0
- package/dist/base/placeholder.js +2 -0
- package/dist/base/placeholder.js.map +1 -1
- package/dist/base/resource-form-schema.d.ts +2 -2
- package/dist/base/searchable.d.ts +3 -2
- package/dist/base/searchable.js +2 -2
- package/dist/base/searchable.js.map +1 -1
- package/dist/base/section.d.ts +6 -2
- package/dist/base/section.js +4 -0
- package/dist/base/section.js.map +1 -1
- package/dist/base/stack.d.ts +6 -0
- package/dist/base/stack.js +6 -0
- package/dist/base/stack.js.map +1 -1
- package/dist/base/stat-group.d.ts +16 -14
- package/dist/base/stat-group.js +2 -0
- package/dist/base/stat-group.js.map +1 -1
- package/dist/base/tab.d.ts +10 -8
- package/dist/base/tab.js +2 -0
- package/dist/base/tab.js.map +1 -1
- package/dist/base/table-view/column-display.d.ts +1 -1
- package/dist/base/table-view/column-display.js.map +1 -1
- package/dist/base/table-view/data-functions.d.ts +10 -4
- package/dist/base/table-view/data-functions.js.map +1 -1
- package/dist/base/table-view/factory.d.ts +5 -0
- package/dist/base/table-view/factory.js +8 -4
- package/dist/base/table-view/factory.js.map +1 -1
- package/dist/base/table-view/internal/auth.d.ts +17 -3
- package/dist/base/table-view/internal/auth.js +26 -5
- package/dist/base/table-view/internal/auth.js.map +1 -1
- package/dist/base/table-view/internal/column-conditions.d.ts +8 -1
- package/dist/base/table-view/internal/column-conditions.js +25 -13
- package/dist/base/table-view/internal/column-conditions.js.map +1 -1
- package/dist/base/table-view/internal/column-display.d.ts +1 -2
- package/dist/base/table-view/internal/column-display.js +3 -9
- package/dist/base/table-view/internal/column-display.js.map +1 -1
- package/dist/base/table-view/internal/factory-helpers.d.ts +1 -1
- package/dist/base/table-view/internal/factory-helpers.js +17 -14
- package/dist/base/table-view/internal/factory-helpers.js.map +1 -1
- package/dist/base/table-view/internal/factory-lifecycle-created.d.ts +2 -3
- package/dist/base/table-view/internal/factory-lifecycle-created.js +5 -5
- package/dist/base/table-view/internal/factory-lifecycle-created.js.map +1 -1
- package/dist/base/table-view/internal/factory-lifecycle-filter.d.ts +2 -2
- package/dist/base/table-view/internal/factory-private-actions.d.ts +2 -2
- package/dist/base/table-view/internal/files.d.ts +2 -1
- package/dist/base/table-view/internal/files.js +14 -5
- package/dist/base/table-view/internal/files.js.map +1 -1
- package/dist/base/table-view/internal/footer.d.ts +3 -3
- package/dist/base/table-view/internal/footer.js +16 -15
- package/dist/base/table-view/internal/footer.js.map +1 -1
- package/dist/base/table-view/internal/guards.d.ts +27 -5
- package/dist/base/table-view/internal/guards.js +133 -49
- package/dist/base/table-view/internal/guards.js.map +1 -1
- package/dist/base/table-view/internal/meta-helpers.d.ts +1 -1
- package/dist/base/table-view/internal/meta-helpers.js +3 -4
- package/dist/base/table-view/internal/meta-helpers.js.map +1 -1
- package/dist/base/table-view/internal/meta.js +2 -3
- package/dist/base/table-view/internal/meta.js.map +1 -1
- package/dist/base/table-view/internal/option-contract.d.ts +9 -1
- package/dist/base/table-view/internal/option-footer.d.ts +2 -2
- package/dist/base/table-view/internal/option-row-actions.d.ts +1 -1
- package/dist/base/table-view/internal/realtime.d.ts +52 -11
- package/dist/base/table-view/internal/realtime.js +23 -16
- package/dist/base/table-view/internal/realtime.js.map +1 -1
- package/dist/base/table-view/internal/resource-form.d.ts +1 -1
- package/dist/base/table-view/internal/resource-form.js +1 -1
- package/dist/base/table-view/internal/resource-form.js.map +1 -1
- package/dist/base/table-view/internal/row-actions-schema.d.ts +12 -12
- package/dist/base/table-view/internal/row-rule-shape.d.ts +11 -5
- package/dist/base/table-view/internal/row-rule-shape.js +60 -30
- package/dist/base/table-view/internal/row-rule-shape.js.map +1 -1
- package/dist/base/table-view/internal/row-rules.d.ts +28 -1
- package/dist/base/table-view/internal/row-rules.js +8 -19
- package/dist/base/table-view/internal/row-rules.js.map +1 -1
- package/dist/base/table-view/internal/tabs.d.ts +1 -1
- package/dist/base/table-view/internal/tabs.js +1 -4
- package/dist/base/table-view/internal/tabs.js.map +1 -1
- package/dist/base/table-view/internal/validation.d.ts +2 -2
- package/dist/base/table-view/internal/validation.js +7 -7
- package/dist/base/table-view/internal/validation.js.map +1 -1
- package/dist/base/table-view/meta.d.ts +7 -6
- package/dist/base/table-view/meta.js +12 -7
- package/dist/base/table-view/meta.js.map +1 -1
- package/dist/base/table-view/resource-form.d.ts +3 -1
- package/dist/base/table-view/resource-form.js +2 -0
- package/dist/base/table-view/resource-form.js.map +1 -1
- package/dist/base/table-view/routes.d.ts +73 -21
- package/dist/base/table-view/routes.js +13 -10
- package/dist/base/table-view/routes.js.map +1 -1
- package/dist/base/table-view/schema.d.ts +157 -152
- package/dist/base/table-view/schema.js +2 -1
- package/dist/base/table-view/schema.js.map +1 -1
- package/dist/base/table-view/source.js +4 -1
- package/dist/base/table-view/source.js.map +1 -1
- package/dist/base/table-view.d.ts +1 -1
- package/dist/base/table-view.js.map +1 -1
- package/dist/base/top-list-card.d.ts +35 -33
- package/dist/base/top-list-card.js +2 -0
- package/dist/base/top-list-card.js.map +1 -1
- package/dist/base/types/error.js +5 -2
- package/dist/base/types/error.js.map +1 -1
- package/dist/base/types/guards.d.ts +4 -4
- package/dist/base/types/json.d.ts +1 -10
- package/dist/base/types/row-action.d.ts +7 -7
- package/dist/component-options/confirm-dialog.d.ts +2 -0
- package/dist/component-options/confirm-dialog.js.map +1 -1
- package/dist/component-options/data-type.d.ts +2 -2
- package/dist/component-options/data-type.js +7 -7
- package/dist/component-options/data-type.js.map +1 -1
- package/dist/component-options/page-layout.d.ts +3 -2
- package/dist/component-options/page-layout.js.map +1 -1
- package/dist/component-options/row-action.d.ts +14 -9
- package/dist/component-slots.d.ts +11 -2
- package/dist/component-slots.js +1 -0
- package/dist/component-slots.js.map +1 -1
- package/dist/component.d.ts +7 -8
- package/dist/component.js +17 -25
- package/dist/component.js.map +1 -1
- package/dist/data-controllers/members.d.ts +11 -7
- package/dist/data-controllers/members.js +1 -1
- package/dist/data-controllers/members.js.map +1 -1
- package/dist/data-controllers/roles.d.ts +32 -10
- package/dist/db/internal/exportJobs.model.d.ts +7 -5
- package/dist/db/internal/inviteResolutions.model.d.ts +7 -5
- package/dist/db/internal/tenantLifecycle.model.d.ts +15 -7
- package/dist/db/internal/tenantLifecycle.model.js +16 -7
- package/dist/db/internal/tenantLifecycle.model.js.map +1 -1
- package/dist/db/models/roles.model.d.ts +7 -5
- package/dist/db/models/tenantMembers.model.d.ts +7 -5
- package/dist/db/models/tenants.model.d.ts +7 -5
- package/dist/db/models/user_invites.model.d.ts +7 -5
- package/dist/guards.d.ts +1 -1
- package/dist/hooks.d.ts +1 -2
- package/dist/hooks.js +33 -26
- package/dist/hooks.js.map +1 -1
- package/dist/internal/attachments.d.ts +2 -2
- package/dist/internal/component-builder.js +2 -1
- package/dist/internal/component-builder.js.map +1 -1
- package/dist/internal/component-serialization.d.ts +2 -4
- package/dist/internal/component-serialization.js +4 -3
- package/dist/internal/component-serialization.js.map +1 -1
- package/dist/internal/component-slots.d.ts +19 -2
- package/dist/internal/component-slots.js +35 -12
- package/dist/internal/component-slots.js.map +1 -1
- package/dist/internal/component-watch-filter.d.ts +11 -0
- package/dist/internal/component-watch-filter.js +22 -0
- package/dist/internal/component-watch-filter.js.map +1 -0
- package/dist/internal/component-watches.js +0 -1
- package/dist/internal/component-watches.js.map +1 -1
- package/dist/internal/own-entry.d.ts +7 -0
- package/dist/internal/own-entry.js +13 -0
- package/dist/internal/own-entry.js.map +1 -0
- package/dist/internal/uploads.d.ts +30 -0
- package/dist/internal/uploads.js +19 -0
- package/dist/internal/uploads.js.map +1 -1
- package/dist/invite-extension-payloads.d.ts +14 -2
- package/dist/invite-extensions/internal/delivery.js +1 -2
- package/dist/invite-extensions/internal/delivery.js.map +1 -1
- package/dist/invite-extensions/internal/edit.d.ts +2 -1
- package/dist/invite-extensions/internal/edit.js +8 -9
- package/dist/invite-extensions/internal/edit.js.map +1 -1
- package/dist/invite-extensions/internal/form-slot.js +8 -15
- package/dist/invite-extensions/internal/form-slot.js.map +1 -1
- package/dist/invite-extensions/internal/payload-slices.d.ts +33 -3
- package/dist/invite-extensions/internal/payload-slices.js +84 -19
- package/dist/invite-extensions/internal/payload-slices.js.map +1 -1
- package/dist/invite-extensions/internal/types.d.ts +10 -1
- package/dist/invite-resolution.js +6 -4
- package/dist/invite-resolution.js.map +1 -1
- package/dist/json.d.ts +10 -0
- package/dist/json.js +3 -0
- package/dist/json.js.map +1 -0
- package/dist/layout-banners.d.ts +5 -2
- package/dist/layout-banners.js.map +1 -1
- package/dist/page/controllers.d.ts +2 -2
- package/dist/page/internal/extension-validation.js +3 -2
- package/dist/page/internal/extension-validation.js.map +1 -1
- package/dist/page/internal/metadata-layout.js +1 -1
- package/dist/page/internal/metadata-layout.js.map +1 -1
- package/dist/page/internal/metadata-publish.js +3 -2
- package/dist/page/internal/metadata-publish.js.map +1 -1
- package/dist/page/internal/metadata-registration.js +5 -4
- package/dist/page/internal/metadata-registration.js.map +1 -1
- package/dist/page/internal/metadata-upload-registration.d.ts +4 -2
- package/dist/page/internal/metadata-upload-registration.js +13 -4
- package/dist/page/internal/metadata-upload-registration.js.map +1 -1
- package/dist/page/internal/metadata-uploads.d.ts +5 -5
- package/dist/page/internal/metadata-uploads.js +4 -8
- package/dist/page/internal/metadata-uploads.js.map +1 -1
- package/dist/page/internal/page-record.d.ts +2 -3
- package/dist/page/internal/page-record.js +23 -16
- package/dist/page/internal/page-record.js.map +1 -1
- package/dist/page/layout-filter.js +17 -6
- package/dist/page/layout-filter.js.map +1 -1
- package/dist/page/metadata.js +5 -7
- package/dist/page/metadata.js.map +1 -1
- package/dist/request-tenant.d.ts +10 -4
- package/dist/request-tenant.js +16 -34
- package/dist/request-tenant.js.map +1 -1
- package/dist/tenant-export.d.ts +2 -1
- package/dist/tenant-lifecycle.d.ts +43 -4
- package/dist/tenant-lifecycle.js +97 -18
- package/dist/tenant-lifecycle.js.map +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/uploads.d.ts +1 -1
- package/dist/uploads.js +39 -60
- package/dist/uploads.js.map +1 -1
- package/dist/utils/fire-and-forget.js.map +1 -1
- package/dist/utils/internal/decorated-class.d.ts +14 -0
- package/dist/utils/internal/decorated-class.js +37 -0
- package/dist/utils/internal/decorated-class.js.map +1 -0
- package/dist/utils/internal/type-check.d.ts +9 -0
- package/dist/utils/internal/type-check.js +13 -5
- package/dist/utils/internal/type-check.js.map +1 -1
- package/dist/utils/internal/value-parser.d.ts +1 -1
- package/dist/utils/internal/value-parser.js +22 -9
- package/dist/utils/internal/value-parser.js.map +1 -1
- package/dist/watch-actions.d.ts +1 -1
- package/docs/1.core/1.introduction.md +82 -77
- package/docs/1.core/10.layout-banners.md +57 -45
- package/docs/1.core/11.modules-and-dynamic-menus.md +178 -0
- package/docs/1.core/12.frontend-modules-and-request-helpers.md +155 -0
- package/docs/1.core/13.tenant-data-export.md +120 -0
- package/docs/1.core/2.pages-and-modules.md +140 -367
- package/docs/1.core/3.components.md +21 -22
- package/docs/1.core/4.permissions.md +92 -71
- package/docs/1.core/5.tenancy.md +150 -86
- package/docs/1.core/6.invites.md +90 -65
- package/docs/1.core/7.hooks.md +96 -166
- package/docs/1.core/8.realtime.md +44 -45
- package/docs/1.core/9.quick-actions.md +37 -30
- package/docs/2.auth/1.introduction.md +33 -35
- package/docs/2.auth/2.authentication.md +60 -38
- package/docs/2.auth/3.tokens-and-sessions.md +56 -55
- package/docs/2.auth/4.users.md +79 -51
- package/docs/2.auth/5.external-identities.md +25 -26
- package/docs/3.base/1.introduction.md +64 -60
- package/docs/3.base/10.display-blocks.md +15 -16
- package/docs/3.base/11.page-layouts.md +270 -0
- package/docs/3.base/12.table-row-actions.md +122 -0
- package/docs/3.base/13.table-filters-and-forms.md +104 -0
- package/docs/3.base/14.table-events-and-helpers.md +114 -0
- package/docs/3.base/15.table-sources-and-gates.md +24 -0
- package/docs/3.base/2.types.md +44 -41
- package/docs/3.base/3.forms.md +27 -28
- package/docs/3.base/4.tables.md +35 -368
- package/docs/3.base/5.charts-and-widgets.md +28 -29
- package/docs/3.base/6.layout.md +21 -270
- package/docs/3.base/8.data-types.md +39 -40
- package/docs/3.base/9.helpers.md +36 -38
- package/docs/4.notifications/1.introduction.md +22 -26
- package/docs/4.notifications/2.categories-and-subjects.md +58 -55
- package/docs/4.notifications/3.sending.md +72 -68
- package/docs/5.html-render/1.introduction.md +119 -81
- package/docs/5.html-render/2.built-in-emails.md +71 -51
- package/docs/index.md +18 -29
- package/docs/tsconfig.json +4 -0
- package/package.json +11 -11
- package/docs/images/emails-admin-invite.png +0 -0
- package/docs/images/emails-change-notice.png +0 -0
- package/docs/images/emails-change-verification.png +0 -0
- package/docs/images/emails-digest-logo-dark.png +0 -0
- package/docs/images/emails-digest-logo-light.png +0 -0
- package/docs/images/emails-digest.png +0 -0
- package/docs/images/emails-export-partial.png +0 -0
- package/docs/images/emails-export-ready.png +0 -0
- package/docs/images/emails-reset-password.png +0 -0
- package/docs/images/emails-two-factor.png +0 -0
- package/docs/images/emails-user-validation.png +0 -0
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Authentication"
|
|
3
|
-
description: "
|
|
3
|
+
description: "The authentication decorators, `authenticateRequestUser`, and the token input they share."
|
|
4
|
+
mode: reference
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# Authentication
|
|
7
|
-
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
|
-
Authentication turns an incoming HTTP request into a `User` row.
|
|
9
|
+
Authentication turns an incoming HTTP request into a `User` row. `@antelopejs/interface-dms/auth` exports one plain function, `authenticateRequestUser`, and four decorators: `AuthRawUser`, `AuthUser`, `IfAuthUser` and `AuthOwnerOnly`. Each of them binds the verified user and tenant to the request, and [`getRequestTenantId`](/docs/interfaces/core/tenancy#resolve-the-requests-tenant) then returns that tenant.
|
|
11
10
|
|
|
12
|
-
All of them read the bearer token from the
|
|
11
|
+
All of them read the bearer token from the `Authorization` header of the request (`Authorization: Bearer <token>`) and run the same two steps:
|
|
13
12
|
|
|
14
|
-
1.
|
|
15
|
-
2.
|
|
13
|
+
1. The authenticator decodes the token into a `TenantTokenInput`: the user id, the tenant id, and the undecoded token itself.
|
|
14
|
+
2. The validator loads the user named by that id and verifies the token against that user. It checks the signature, checks that the token was issued as an access token, and checks that the session the token names still exists. It then applies the extra requirement of the decorator.
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
The decorator injects whatever the validator returns. The four decorators differ only in the requirement they enforce and in what they do when it fails.
|
|
18
17
|
|
|
19
|
-
The `User` type they inject comes from
|
|
18
|
+
The `User` type they inject comes from `@antelopejs/interface-dms/auth/db` and is described in [Users](/docs/interfaces/auth/users). The generators in [Tokens and sessions](/docs/interfaces/auth/tokens-and-sessions) produce the tokens they consume.
|
|
20
19
|
|
|
21
|
-
## Require an
|
|
20
|
+
## Require an authenticated user
|
|
22
21
|
|
|
23
|
-
`AuthUser` injects the `User
|
|
22
|
+
`AuthUser` injects the `User`, and enforces email validation when the deployment sets `auth.mustValidateEmail`. A caller whose email is not validated then gets `401` (`Email not validated`). Use it on any route that must have a signed-in caller.
|
|
24
23
|
|
|
25
24
|
```typescript
|
|
26
25
|
import { Controller, Get } from "@antelopejs/interface-api";
|
|
@@ -36,11 +35,11 @@ export class ProfileController extends Controller("/api/profile") {
|
|
|
36
35
|
}
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
The injected value is the full `User` row, including fields you
|
|
38
|
+
The injected value is the full `User` row, including fields you must not return over HTTP. Pass it through `sanitizeUser` before you serialize it, as described in [Users](/docs/interfaces/auth/users).
|
|
40
39
|
|
|
41
|
-
## Skip the
|
|
40
|
+
## Skip the email-validation gate
|
|
42
41
|
|
|
43
|
-
`AuthRawUser` resolves the same `User` but does not apply the email-validation requirement.
|
|
42
|
+
`AuthRawUser` resolves the same `User` but does not apply the email-validation requirement. The routes that exist because the email is not validated yet use it: reading the current account, logging out, and requesting a new validation email. Modules also use it to gate their own API routes on a signed-in caller.
|
|
44
43
|
|
|
45
44
|
```typescript
|
|
46
45
|
import { Controller, Get, Post } from "@antelopejs/interface-api";
|
|
@@ -65,11 +64,11 @@ export class AccountController extends Controller("/api/account") {
|
|
|
65
64
|
}
|
|
66
65
|
```
|
|
67
66
|
|
|
68
|
-
Both decorators inject the raw database row
|
|
67
|
+
Both decorators inject the raw database row, and neither strips sensitive fields. "Raw" refers to the skipped email-validation step, not to the shape of the object.
|
|
69
68
|
|
|
70
|
-
## Accept
|
|
69
|
+
## Accept anonymous callers
|
|
71
70
|
|
|
72
|
-
`IfAuthUser` is the optional variant. It injects `User | undefined` and does not reject the request
|
|
71
|
+
`IfAuthUser` is the optional variant. It injects `User | undefined` and does not reject the request. A missing token, a malformed token, and a token that fails validation all resolve to `undefined`.
|
|
73
72
|
|
|
74
73
|
```typescript
|
|
75
74
|
import { Controller, Get } from "@antelopejs/interface-api";
|
|
@@ -87,11 +86,11 @@ export class ArticleController extends Controller("/api/articles") {
|
|
|
87
86
|
}
|
|
88
87
|
```
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
An expired token resolves to `undefined`, not to a 401. A client-side refresh interceptor that reacts to 401 responses therefore does not fire on a route guarded this way. When a route must fail on an expired session, guard it with `AuthUser` and give the anonymous path its own route.
|
|
91
90
|
|
|
92
|
-
## Restrict a
|
|
91
|
+
## Restrict a route to platform owners
|
|
93
92
|
|
|
94
|
-
`AuthOwnerOnly` requires the authenticated user to be a platform owner (`User.owner === true`). It answers `401` when no token is provided and `403` when the caller is authenticated but not an owner. The DMS applies it to pages
|
|
93
|
+
`AuthOwnerOnly` requires the authenticated user to be a platform owner (`User.owner === true`). It answers `401` when no token is provided and `403` (`Owner-only`) when the caller is authenticated but not an owner. The DMS applies it to the pages a module declares (`/modules/<id>/...`), which are owner-only administration spaces, unless the page is public or declares `authOnly`.
|
|
95
94
|
|
|
96
95
|
```typescript
|
|
97
96
|
import { Controller, Get } from "@antelopejs/interface-api";
|
|
@@ -109,11 +108,11 @@ export class MaintenanceController extends Controller("/api/maintenance") {
|
|
|
109
108
|
}
|
|
110
109
|
```
|
|
111
110
|
|
|
112
|
-
`AuthOwnerOnly` is a plain function that returns a ready
|
|
111
|
+
`AuthOwnerOnly` is a plain function that returns a decorator ready to apply, so you write `@AuthOwnerOnly()` like the three decorator factories above. It takes no arguments, because it supplies its own validator.
|
|
113
112
|
|
|
114
|
-
## Gate
|
|
113
|
+
## Gate every route on a controller
|
|
115
114
|
|
|
116
|
-
`AuthRawUser`, `AuthUser` and `IfAuthUser`
|
|
115
|
+
`AuthRawUser`, `AuthUser` and `IfAuthUser` apply to a parameter, to a property, or to the controller class itself. A property provider is a computed property of the controller. It is resolved on every request the controller handles, whether or not the handler reads it. A decorated property therefore gates the whole controller and gives the handlers a typed `this.user`.
|
|
117
116
|
|
|
118
117
|
```typescript
|
|
119
118
|
import { Controller, Get, JSONBody, Post } from "@antelopejs/interface-api";
|
|
@@ -144,11 +143,11 @@ export class SettingsController extends Controller("/api/settings") {
|
|
|
144
143
|
}
|
|
145
144
|
```
|
|
146
145
|
|
|
147
|
-
|
|
146
|
+
The DMS uses this form when it wires authentication onto a page controller. It applies the decorator to the `user` property of the page class.
|
|
148
147
|
|
|
149
|
-
## Read the
|
|
148
|
+
## Read the token payload
|
|
150
149
|
|
|
151
|
-
`TenantTokenInput` is the value the authenticator step produces and the validator step consumes. It is exported from
|
|
150
|
+
`TenantTokenInput` is the value the authenticator step produces and the validator step consumes. It is exported from `@antelopejs/interface-dms/auth`.
|
|
152
151
|
|
|
153
152
|
```typescript
|
|
154
153
|
export interface TenantTokenInput {
|
|
@@ -160,17 +159,17 @@ export interface TenantTokenInput {
|
|
|
160
159
|
|
|
161
160
|
| Field | Type | Description |
|
|
162
161
|
| ----- | ---- | ----------- |
|
|
163
|
-
| `tenantId` | `string` | The tenant the token was issued for, taken from the
|
|
162
|
+
| `tenantId` | `string` | The tenant the token was issued for, taken from the `tenantId` claim of the token. |
|
|
164
163
|
| `id` | `string` | The `_id` of the user the token was issued for. |
|
|
165
164
|
| `rawToken` | `string` | The undecoded bearer token, used to verify the signature against the user. |
|
|
166
165
|
|
|
167
|
-
The decoded payload carries no signature guarantee on its own
|
|
166
|
+
The decoded payload carries no signature guarantee on its own. The validator is the step that verifies `rawToken` against the user it names.
|
|
168
167
|
|
|
169
|
-
## Authenticate
|
|
168
|
+
## Authenticate inside a custom provider
|
|
170
169
|
|
|
171
|
-
`authenticateRequestUser`
|
|
170
|
+
`authenticateRequestUser` runs the same authenticator and validator outside a decorator. Use it when you write your own parameter provider and need the user and something else in one place.
|
|
172
171
|
|
|
173
|
-
```typescript
|
|
172
|
+
```typescript fragment
|
|
174
173
|
authenticateRequestUser(ctx: RequestContext): Promise<User>
|
|
175
174
|
```
|
|
176
175
|
|
|
@@ -178,7 +177,7 @@ authenticateRequestUser(ctx: RequestContext): Promise<User>
|
|
|
178
177
|
| --------- | ----------- |
|
|
179
178
|
| `ctx` | The request context handed to a parameter provider, from `@antelopejs/interface-api`. The function reads `ctx.rawRequest.headers.authorization`. |
|
|
180
179
|
|
|
181
|
-
It runs the same validation as `AuthUser`, so the email-validation gate applies
|
|
180
|
+
It runs the same validation as `AuthUser`, so the email-validation gate applies. A caller whose email is not validated is rejected when the deployment requires validation. Every failure throws an `HTTPResult` with status `401`. It also throws `401` when the request is already bound to another user or tenant.
|
|
182
181
|
|
|
183
182
|
```typescript
|
|
184
183
|
import {
|
|
@@ -204,19 +203,42 @@ export const AuthBetaTester = MakeParameterAndPropertyDecorator(
|
|
|
204
203
|
);
|
|
205
204
|
```
|
|
206
205
|
|
|
207
|
-
|
|
206
|
+
The DMS builds its tenant guards the same way. `AuthTenantOwner` and `AuthTenantMember` in `@antelopejs/interface-dms/guards` authenticate the request, then resolve its tenant and check the caller's membership.
|
|
207
|
+
|
|
208
|
+
A provider is also the way to add a requirement and keep the built-in one. A call site can pass a replacement validator, as in `@AuthUser(callback)`. That callback replaces the whole validation step, signature check included, and its return type is `boolean | User`. Such a call binds no tenant to the request. This interface exports no token-verification function, so a replacement validator cannot redo the signature check it removes.
|
|
209
|
+
|
|
210
|
+
## Accept another credential family
|
|
211
|
+
|
|
212
|
+
`@antelopejs/interface-dms/auth` also exports the `RequestPrincipal` and `RequestAuthenticator` types. A `RequestAuthenticator` lets one route accept a credential that is not a DMS JWT. The decorators on this page accept only the DMS JWT. To accept another credential, pass authenticators to `authenticateTenantRequest` in `@antelopejs/interface-dms/guards`, through its `authenticators` option.
|
|
213
|
+
|
|
214
|
+
```typescript fragment
|
|
215
|
+
interface RequestPrincipal {
|
|
216
|
+
user: User;
|
|
217
|
+
tenantId: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
interface RequestAuthenticator {
|
|
221
|
+
recognizes(token: string): boolean;
|
|
222
|
+
authenticate(token: string): Promise<RequestPrincipal>;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
| Member | Contract |
|
|
227
|
+
| ------ | -------- |
|
|
228
|
+
| `recognizes` | Claims the credential family from the bearer token, without trusting its contents. It must also recognize a malformed credential of its own family. |
|
|
229
|
+
| `authenticate` | Verifies the credential and reloads its user. It throws on an invalid, expired or revoked credential. |
|
|
208
230
|
|
|
209
|
-
A
|
|
231
|
+
A token that no authenticator recognizes falls back to the DMS JWT. A token that two authenticators recognize is refused with `401`. A principal is identity and tenant established together. It is not an authorization.
|
|
210
232
|
|
|
211
|
-
## Decorator
|
|
233
|
+
## Decorator reference
|
|
212
234
|
|
|
213
235
|
| Decorator | Injects | Email validation | On failure |
|
|
214
236
|
| --------- | ------- | ---------------- | ---------- |
|
|
215
237
|
| `AuthRawUser()` | `User` | Not checked | `401` |
|
|
216
238
|
| `AuthUser()` | `User` | Enforced when the configuration requires it | `401` |
|
|
217
239
|
| `IfAuthUser()` | `User \| undefined` | Enforced when the configuration requires it | Resolves to `undefined` |
|
|
218
|
-
| `AuthOwnerOnly()` | `User` | Enforced when the configuration requires it | `401` without a token, `403` when not an owner |
|
|
240
|
+
| `AuthOwnerOnly()` | `User` | Enforced when the configuration requires it | `401` without a valid token, `403` when not an owner |
|
|
219
241
|
|
|
220
|
-
## Next
|
|
242
|
+
## Next steps
|
|
221
243
|
|
|
222
|
-
Continue with [Tokens and
|
|
244
|
+
Continue with [Tokens and sessions](/docs/interfaces/auth/tokens-and-sessions) to see how the DMS issues and validates the tokens these decorators consume.
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Tokens and
|
|
3
|
-
description: "The
|
|
2
|
+
title: "Tokens and sessions"
|
|
3
|
+
description: "The four token kinds, their generators and validators, the token payload, and the `Session` table and model."
|
|
4
|
+
mode: reference
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# Tokens and Sessions
|
|
7
|
-
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
|
-
The interface issues four kinds of token, and it records a login as a row in the `sessions` table. Three of the four
|
|
9
|
+
The interface issues four kinds of token, and it records a login as a row in the `sessions` table. Three of the four token kinds have an exported validator. The authentication decorators validate the access token.
|
|
11
10
|
|
|
12
11
|
| Token | Generated by | Validated by | Carries |
|
|
13
12
|
| ----- | ------------ | ------------ | ------- |
|
|
14
|
-
| Access | `generateAccessToken` | The authentication decorators in [Authentication](/docs/interfaces/auth/authentication) | `id`, `tenantId`, optional `sessionId
|
|
15
|
-
| Refresh | `generateRefreshToken` | `validateRefreshToken` | `id`, `tenantId`, optional `sessionId
|
|
13
|
+
| Access | `generateAccessToken` | The authentication decorators in [Authentication](/docs/interfaces/auth/authentication) | `id`, `tenantId`, optional `sessionId`, a purpose marker |
|
|
14
|
+
| Refresh | `generateRefreshToken` | `validateRefreshToken` | `id`, `tenantId`, optional `sessionId`, a purpose marker |
|
|
16
15
|
| Two-factor | `generateTwoFactorToken` | `validateTwoFactorToken` | `id`, `tenantId`, a purpose marker |
|
|
17
16
|
| Tenant assignment | `generateTenantAssignmentToken` | `validateTenantAssignmentToken` | `id`, a purpose marker |
|
|
18
17
|
|
|
19
|
-
Every generator takes the `User` it signs for, and every validator loads that user
|
|
18
|
+
Every generator takes the `User` it signs for, and every validator loads that user before it returns. All seven functions are interface functions, so every call returns a promise. The purpose marker keeps one kind of token from being accepted as another. A refresh token sent as a bearer token fails authentication, for example.
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
A client holds the access and refresh pair. The access token goes in the `Authorization` header of ordinary requests, and the refresh token gets a new access token when the old one expires. Two-factor and tenant-assignment tokens are short-lived steps between a password check and a real session.
|
|
22
21
|
|
|
23
|
-
## Issue an
|
|
22
|
+
## Issue an access and refresh token pair
|
|
24
23
|
|
|
25
|
-
```typescript
|
|
24
|
+
```typescript fragment
|
|
26
25
|
generateAccessToken(
|
|
27
26
|
tenantId: string,
|
|
28
27
|
user: User,
|
|
@@ -38,11 +37,11 @@ generateRefreshToken(
|
|
|
38
37
|
|
|
39
38
|
| Parameter | Description |
|
|
40
39
|
| --------- | ----------- |
|
|
41
|
-
| `tenantId` | The tenant the token is scoped to. It
|
|
42
|
-
| `user` | The `User` the token is issued for. The user's `authKey`
|
|
43
|
-
| `sessionId` | The `_id` of the `Session` row that records this login. Optional
|
|
40
|
+
| `tenantId` | The tenant the token is scoped to. It goes in the `tenantId` claim of the token, and the request's tenant resolution reads it back. |
|
|
41
|
+
| `user` | The `User` the token is issued for. The user's `authKey` is part of the signing secret, so rotating `authKey` invalidates every token issued to that user before. |
|
|
42
|
+
| `sessionId` | The `_id` of the `Session` row that records this login. Optional. A token issued without it is valid but is not tied to a revocable session. An access token issued with it is refused as soon as that row is deleted. |
|
|
44
43
|
|
|
45
|
-
Both return the signed `token
|
|
44
|
+
Both functions return the signed `token`, and its lifetime as `expiresIn` in milliseconds. The lifetimes come from the `accessTokenLifetime` and `refreshTokenLifetime` settings of the deployment.
|
|
46
45
|
|
|
47
46
|
```typescript
|
|
48
47
|
import {
|
|
@@ -79,15 +78,15 @@ export async function startSession(
|
|
|
79
78
|
}
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
## Validate a
|
|
81
|
+
## Validate a refresh token
|
|
83
82
|
|
|
84
|
-
```typescript
|
|
83
|
+
```typescript fragment
|
|
85
84
|
validateRefreshToken(
|
|
86
85
|
token: string,
|
|
87
86
|
): Promise<{ id: string; tenantId: string; sessionId?: string }>
|
|
88
87
|
```
|
|
89
88
|
|
|
90
|
-
The function decodes the token, loads the user it names, and verifies the signature against that user. It throws `HTTPResult(401)` when the user no longer exists
|
|
89
|
+
The function decodes the token, loads the user it names, and verifies the signature against that user. It also checks that the token was issued as a refresh token and carries non-empty `id` and `tenantId` claims. It throws `HTTPResult(401)` when the user no longer exists (`Invalid user`), and when the token is malformed, expired, badly signed or issued for another purpose. It returns the claims only. The caller must still confirm three things: that the session exists, that the token is its current one (`isCurrentRefreshToken`), and that the user still has access to `tenantId`.
|
|
91
90
|
|
|
92
91
|
```typescript
|
|
93
92
|
import { HTTPResult } from "@antelopejs/interface-api";
|
|
@@ -130,13 +129,13 @@ export async function refresh(
|
|
|
130
129
|
}
|
|
131
130
|
```
|
|
132
131
|
|
|
133
|
-
|
|
132
|
+
The returned payload names a `tenantId`, so the same call also backs a tenant switch. Validate the refresh token, check the user's membership of the target tenant, then issue a new pair for that tenant.
|
|
134
133
|
|
|
135
|
-
## Hand
|
|
134
|
+
## Hand off to a second factor
|
|
136
135
|
|
|
137
|
-
When a user
|
|
136
|
+
When the credentials of a user check out but the account has second factors enabled, issue a two-factor token instead of a session. The client then comes back with the code.
|
|
138
137
|
|
|
139
|
-
```typescript
|
|
138
|
+
```typescript fragment
|
|
140
139
|
generateTwoFactorToken(
|
|
141
140
|
tenantId: string,
|
|
142
141
|
user: User,
|
|
@@ -150,7 +149,7 @@ validateTwoFactorToken(token: string): Promise<{
|
|
|
150
149
|
}>
|
|
151
150
|
```
|
|
152
151
|
|
|
153
|
-
`validateTwoFactorToken` rejects a token that was not issued for the two-factor purpose
|
|
152
|
+
A two-factor token lives five minutes, and `expiresIn` gives that lifetime in milliseconds. `validateTwoFactorToken` rejects a token that was not issued for the two-factor purpose. It resolves the `User` for you, so the verification route can read `twoFactorMethods`, `twoFactorSecret` and the other fields without a second lookup. Whatever is wrong with the token, it throws the same `HTTPResult(401, "error.invalid_2fa_token")`: not a JWT, unknown user, bad signature, expired, or another purpose. A caller therefore cannot tell which user ids exist.
|
|
154
153
|
|
|
155
154
|
```typescript
|
|
156
155
|
import { createHash } from "node:crypto";
|
|
@@ -192,13 +191,13 @@ export async function requestEmailCode(
|
|
|
192
191
|
}
|
|
193
192
|
```
|
|
194
193
|
|
|
195
|
-
Once the code checks out, the route issues a real access and refresh pair
|
|
194
|
+
Once the code checks out, the route issues a real access and refresh pair for the `tenantId` the two-factor token carried. [Users](/docs/interfaces/auth/users) covers `send2FAEmail` and the other mail functions.
|
|
196
195
|
|
|
197
|
-
## Hand
|
|
196
|
+
## Hand off tenant assignment
|
|
198
197
|
|
|
199
|
-
A user whose credentials are valid but who belongs to no tenant yet cannot receive an access token, because an access token is always scoped to a tenant. `generateTenantAssignmentToken`
|
|
198
|
+
A user whose credentials are valid but who belongs to no tenant yet cannot receive an access token, because an access token is always scoped to a tenant. `generateTenantAssignmentToken` fills that gap. It signs the user without a tenant claim, so an onboarding flow can pick or create a tenant.
|
|
200
199
|
|
|
201
|
-
```typescript
|
|
200
|
+
```typescript fragment
|
|
202
201
|
generateTenantAssignmentToken(
|
|
203
202
|
user: User,
|
|
204
203
|
): Promise<{ token: string; expiresIn: number }>
|
|
@@ -206,7 +205,7 @@ generateTenantAssignmentToken(
|
|
|
206
205
|
validateTenantAssignmentToken(token: string): Promise<{ id: string; user: User }>
|
|
207
206
|
```
|
|
208
207
|
|
|
209
|
-
`validateTenantAssignmentToken` rejects a token that was not issued for the tenant-assignment purpose and returns the user id together with the loaded `User`. Like the two-factor check, every refusal is the same `HTTPResult(401, "Invalid tenant assignment token")`.
|
|
208
|
+
A tenant-assignment token lives fifteen minutes. `validateTenantAssignmentToken` rejects a token that was not issued for the tenant-assignment purpose, and returns the user id together with the loaded `User`. Like the two-factor check, every refusal is the same `HTTPResult(401, "Invalid tenant assignment token")`.
|
|
210
209
|
|
|
211
210
|
```typescript
|
|
212
211
|
import {
|
|
@@ -231,7 +230,7 @@ export async function completeTenantAssignment(
|
|
|
231
230
|
}
|
|
232
231
|
```
|
|
233
232
|
|
|
234
|
-
## The
|
|
233
|
+
## The token payload
|
|
235
234
|
|
|
236
235
|
`JwtUserPayload` describes the claims an access or refresh token carries about its subject. Use it as the target type when you decode a token yourself.
|
|
237
236
|
|
|
@@ -247,15 +246,15 @@ export interface JwtUserPayload {
|
|
|
247
246
|
| ----- | ---- | ----------- |
|
|
248
247
|
| `id` | `string` | The `_id` of the user the token was issued for. |
|
|
249
248
|
| `tenantId` | `string` | The tenant the token is scoped to. |
|
|
250
|
-
| `sessionId` | `string \| undefined` | The `Session` row
|
|
249
|
+
| `sessionId` | `string \| undefined` | The `Session` row behind the token, when the token was issued with one. |
|
|
251
250
|
|
|
252
|
-
`TenantTokenInput
|
|
251
|
+
`TenantTokenInput`, from [Authentication](/docs/interfaces/auth/authentication), describes the same subject from the other side. It is what a validator receives: `id` and `tenantId`, plus the undecoded `rawToken`. `JwtUserPayload` is what the token itself says. The two types share `id` and `tenantId`, and neither is a subset of the other.
|
|
253
252
|
|
|
254
|
-
## Record a
|
|
253
|
+
## Record a login session
|
|
255
254
|
|
|
256
|
-
`createSession` inserts a `Session` row for a login and returns its `_id
|
|
255
|
+
`createSession` inserts a `Session` row for a login and returns its `_id`. Pass that id as the `sessionId` of the token pair.
|
|
257
256
|
|
|
258
|
-
```typescript
|
|
257
|
+
```typescript fragment
|
|
259
258
|
createSession(
|
|
260
259
|
sessionModel: SessionModel,
|
|
261
260
|
userId: string,
|
|
@@ -268,14 +267,14 @@ createSession(
|
|
|
268
267
|
| --------- | ----------- |
|
|
269
268
|
| `sessionModel` | The `SessionModel` instance to insert through. |
|
|
270
269
|
| `userId` | The `_id` of the user logging in. |
|
|
271
|
-
| `userAgent` | The
|
|
272
|
-
| `ip` | The
|
|
270
|
+
| `userAgent` | The `User-Agent` header of the request. The DMS parses it into the `browser`, `os` and `deviceType` fields and keeps the raw string in `userAgent`. |
|
|
271
|
+
| `ip` | The IP address of the caller, stored as given. |
|
|
273
272
|
|
|
274
|
-
The row starts with an empty `
|
|
273
|
+
The row starts with no refresh token hash, an empty `location`, and `createdAt` and `lastActiveAt` set to the current time. Record the refresh token with `sessionModel.replaceRefreshToken` once you have generated it, as in the first example on this page.
|
|
275
274
|
|
|
276
|
-
## The
|
|
275
|
+
## The session table
|
|
277
276
|
|
|
278
|
-
`Session` is registered as the `sessions` table
|
|
277
|
+
`Session` is registered as the `sessions` table in the DMS core schema. Its rows are shared across tenants, and you obtain its model without a tenant instance. The class, its table-name constant and its model all live in `@antelopejs/interface-dms/auth/db`.
|
|
279
278
|
|
|
280
279
|
```typescript
|
|
281
280
|
import {
|
|
@@ -287,10 +286,12 @@ import {
|
|
|
287
286
|
|
|
288
287
|
| Field | Type | Description |
|
|
289
288
|
| ----- | ---- | ----------- |
|
|
290
|
-
| `_id` | `string` | Primary key. This
|
|
291
|
-
| `userId` | `string` | The owning user
|
|
292
|
-
| `refreshTokenHash` | `string \| null
|
|
293
|
-
| `sealedRefreshToken` | `string \| null
|
|
289
|
+
| `_id` | `string` | Primary key. This value travels in the `sessionId` claim of the token. |
|
|
290
|
+
| `userId` | `string` | The `_id` of the owning user. Indexed, and declared as a relation to the `User` table. |
|
|
291
|
+
| `refreshTokenHash` | `string \| null`, optional | SHA-256 of the refresh token currently valid for this session. A refresh matches against it, which makes the session revocable. The token itself is never stored. |
|
|
292
|
+
| `sealedRefreshToken` | `string \| null`, optional | The current refresh token, encrypted under a key derived from its predecessor. A client that still holds the predecessor during the rotation grace window can get the current token back. Without the predecessor, the value is unreadable. |
|
|
293
|
+
| `previousRefreshTokenHash` | `string \| null`, optional | SHA-256 of the refresh token the last rotation replaced. |
|
|
294
|
+
| `refreshTokenRotatedAt` | `Date \| null`, optional | When the last rotation happened. It starts the grace window. |
|
|
294
295
|
| `userAgent` | `string` | The raw `User-Agent` string captured at login. |
|
|
295
296
|
| `ip` | `string` | The IP address captured at login. |
|
|
296
297
|
| `browser` | `string` | Browser name and version parsed from `userAgent`, or `"Unknown"`. |
|
|
@@ -298,23 +299,23 @@ import {
|
|
|
298
299
|
| `deviceType` | `string` | Device class parsed from `userAgent`: `"mobile"`, `"tablet"`, or `"desktop"` when neither applies. |
|
|
299
300
|
| `location` | `string` | Free-form location label. `createSession` leaves it empty. |
|
|
300
301
|
| `createdAt` | `Date` | Set on insert by the creation-time decorator. Indexed. |
|
|
301
|
-
| `lastActiveAt` | `Date` |
|
|
302
|
+
| `lastActiveAt` | `Date` | The last time the session was used. Refresh handlers update it. Indexed. Every day at 03:30, a DMS job deletes the sessions last active longer ago than `refreshTokenLifetime`. |
|
|
302
303
|
|
|
303
304
|
`SESSIONS_TABLE_NAME` holds the table name, `"sessions"`.
|
|
304
305
|
|
|
305
|
-
`isCurrentRefreshToken(session, token)` tells whether a presented token is the
|
|
306
|
+
`isCurrentRefreshToken(session, token)` tells whether a presented token is the current one of the session. It compares hashes in constant time, and returns `false` when the session has no `refreshTokenHash`.
|
|
306
307
|
|
|
307
|
-
## Query
|
|
308
|
+
## Query sessions with `SessionModel`
|
|
308
309
|
|
|
309
|
-
`SessionModel` extends `BasicDataModel(Session, SESSIONS_TABLE_NAME)
|
|
310
|
+
`SessionModel` extends `BasicDataModel(Session, SESSIONS_TABLE_NAME)`. It has the standard `get`, `getBy`, `getAll`, `insert`, `update` and `delete` operations, plus the refresh-token operations and two lookups by user.
|
|
310
311
|
|
|
311
312
|
| Method | Signature | Description |
|
|
312
313
|
| ------ | --------- | ----------- |
|
|
313
|
-
| `replaceRefreshToken` | `(sessionId: string, refreshToken: string) => Promise<void>` |
|
|
314
|
-
| `rotateRefreshToken` | `(sessionId: string, presentedToken: string, refreshToken: string, rotatedAt?: Date) => Promise<string \| null>` |
|
|
315
|
-
| `deleteInactiveSince` | `(threshold: Date) => Promise<void>` |
|
|
316
|
-
| `getByUserId` | `(userId: string) => Promise<Session[]>` | Every session
|
|
317
|
-
| `deleteByUserId` | `(userId: string) => Promise<void>` |
|
|
314
|
+
| `replaceRefreshToken` | `(sessionId: string, refreshToken: string) => Promise<void>` | Makes a token the current one of the session, storing only its hash. Clears the sealed token and the predecessor, so no grace window applies. |
|
|
315
|
+
| `rotateRefreshToken` | `(sessionId: string, presentedToken: string, refreshToken: string, rotatedAt?: Date) => Promise<string \| null>` | Replaces the presented token with a new one in one atomic update, and sets `lastActiveAt`. A client that presents the immediate predecessor within the 15-second grace window gets the current token back. Any other token gets `null`. |
|
|
316
|
+
| `deleteInactiveSince` | `(threshold: Date) => Promise<void>` | Deletes the sessions last active before a date. |
|
|
317
|
+
| `getByUserId` | `(userId: string) => Promise<Session[]>` | Every session of a user, read through the `userId` index. |
|
|
318
|
+
| `deleteByUserId` | `(userId: string) => Promise<void>` | Deletes every session of a user. |
|
|
318
319
|
|
|
319
320
|
```typescript
|
|
320
321
|
import { Controller, Delete, Get } from "@antelopejs/interface-api";
|
|
@@ -345,8 +346,8 @@ export class SessionsController extends Controller("/api/sessions") {
|
|
|
345
346
|
}
|
|
346
347
|
```
|
|
347
348
|
|
|
348
|
-
Deleting a session stops refreshes
|
|
349
|
+
Deleting a session stops its refreshes, and cuts off the access tokens issued for it at once. The authentication decorators refuse an access token whose `sessionId` no longer names a session of its user. A token issued without a `sessionId` stays valid until it expires. To cut those tokens off too, rotate the user's `authKey`, as described in [Users](/docs/interfaces/auth/users).
|
|
349
350
|
|
|
350
|
-
## Next
|
|
351
|
+
## Next steps
|
|
351
352
|
|
|
352
|
-
Continue with [Users](/docs/interfaces/auth/users) for the `User` table, `UserModel`, `sanitizeUser`, and the account mail
|
|
353
|
+
Continue with [Users](/docs/interfaces/auth/users) for the `User` table, `UserModel`, `sanitizeUser`, and the account mail functions.
|