@techelusive/nest-auth 0.0.0-stage → 0.2.1
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 +71 -0
- package/LICENSE +21 -0
- package/README.md +204 -2
- package/api/openapi.json +4399 -0
- package/api/techelusive-authentication.postman_collection.json +3178 -0
- package/dist/auth-options.d.ts +156 -0
- package/dist/auth-options.js +3 -0
- package/dist/auth-options.js.map +1 -0
- package/dist/auth-options.validation.d.ts +9 -0
- package/dist/auth-options.validation.js +74 -0
- package/dist/auth-options.validation.js.map +1 -0
- package/dist/auth.module.d.ts +38 -0
- package/dist/auth.module.js +173 -0
- package/dist/auth.module.js.map +1 -0
- package/dist/common/auth-error.d.ts +16 -0
- package/dist/common/auth-error.js +23 -0
- package/dist/common/auth-error.js.map +1 -0
- package/dist/common/auth-exception.filter.d.ts +24 -0
- package/dist/common/auth-exception.filter.js +66 -0
- package/dist/common/auth-exception.filter.js.map +1 -0
- package/dist/common/crypto/jwt.d.ts +89 -0
- package/dist/common/crypto/jwt.js +144 -0
- package/dist/common/crypto/jwt.js.map +1 -0
- package/dist/common/crypto/random-secrets.d.ts +78 -0
- package/dist/common/crypto/random-secrets.js +113 -0
- package/dist/common/crypto/random-secrets.js.map +1 -0
- package/dist/common/crypto/remote-public-keys.d.ts +49 -0
- package/dist/common/crypto/remote-public-keys.js +105 -0
- package/dist/common/crypto/remote-public-keys.js.map +1 -0
- package/dist/common/crypto/totp.d.ts +68 -0
- package/dist/common/crypto/totp.js +148 -0
- package/dist/common/crypto/totp.js.map +1 -0
- package/dist/common/encryption.service.d.ts +36 -0
- package/dist/common/encryption.service.js +111 -0
- package/dist/common/encryption.service.js.map +1 -0
- package/dist/common/identifiers.d.ts +48 -0
- package/dist/common/identifiers.js +89 -0
- package/dist/common/identifiers.js.map +1 -0
- package/dist/common/network-safety.d.ts +19 -0
- package/dist/common/network-safety.js +72 -0
- package/dist/common/network-safety.js.map +1 -0
- package/dist/common/rate-limiter.service.d.ts +63 -0
- package/dist/common/rate-limiter.service.js +158 -0
- package/dist/common/rate-limiter.service.js.map +1 -0
- package/dist/common/refresh-token-cookie.d.ts +78 -0
- package/dist/common/refresh-token-cookie.js +185 -0
- package/dist/common/refresh-token-cookie.js.map +1 -0
- package/dist/common/request-context.d.ts +14 -0
- package/dist/common/request-context.js +22 -0
- package/dist/common/request-context.js.map +1 -0
- package/dist/common/strict-validation.pipe.d.ts +8 -0
- package/dist/common/strict-validation.pipe.js +16 -0
- package/dist/common/strict-validation.pipe.js.map +1 -0
- package/dist/common/time.d.ts +15 -0
- package/dist/common/time.js +34 -0
- package/dist/common/time.js.map +1 -0
- package/dist/constants.d.ts +1326 -0
- package/dist/constants.js +1142 -0
- package/dist/constants.js.map +1 -0
- package/dist/database/create-auth-tables.migration.d.ts +26 -0
- package/dist/database/create-auth-tables.migration.js +291 -0
- package/dist/database/create-auth-tables.migration.js.map +1 -0
- package/dist/database/email-change-and-retention.migration.d.ts +25 -0
- package/dist/database/email-change-and-retention.migration.js +54 -0
- package/dist/database/email-change-and-retention.migration.js.map +1 -0
- package/dist/database/entities/api-key.entity.d.ts +17 -0
- package/dist/database/entities/api-key.entity.js +80 -0
- package/dist/database/entities/api-key.entity.js.map +1 -0
- package/dist/database/entities/audit-log.entity.d.ts +13 -0
- package/dist/database/entities/audit-log.entity.js +64 -0
- package/dist/database/entities/audit-log.entity.js.map +1 -0
- package/dist/database/entities/backup-code.entity.d.ts +9 -0
- package/dist/database/entities/backup-code.entity.js +52 -0
- package/dist/database/entities/backup-code.entity.js.map +1 -0
- package/dist/database/entities/index.d.ts +43 -0
- package/dist/database/entities/index.js +82 -0
- package/dist/database/entities/index.js.map +1 -0
- package/dist/database/entities/json-object.d.ts +12 -0
- package/dist/database/entities/json-object.js +3 -0
- package/dist/database/entities/json-object.js.map +1 -0
- package/dist/database/entities/link-token.entity.d.ts +15 -0
- package/dist/database/entities/link-token.entity.js +64 -0
- package/dist/database/entities/link-token.entity.js.map +1 -0
- package/dist/database/entities/one-time-code.entity.d.ts +16 -0
- package/dist/database/entities/one-time-code.entity.js +69 -0
- package/dist/database/entities/one-time-code.entity.js.map +1 -0
- package/dist/database/entities/organization-invitation.entity.d.ts +14 -0
- package/dist/database/entities/organization-invitation.entity.js +73 -0
- package/dist/database/entities/organization-invitation.entity.js.map +1 -0
- package/dist/database/entities/organization-member.entity.d.ts +9 -0
- package/dist/database/entities/organization-member.entity.js +48 -0
- package/dist/database/entities/organization-member.entity.js.map +1 -0
- package/dist/database/entities/organization.entity.d.ts +12 -0
- package/dist/database/entities/organization.entity.js +58 -0
- package/dist/database/entities/organization.entity.js.map +1 -0
- package/dist/database/entities/passkey.entity.d.ts +19 -0
- package/dist/database/entities/passkey.entity.js +78 -0
- package/dist/database/entities/passkey.entity.js.map +1 -0
- package/dist/database/entities/password.entity.d.ts +6 -0
- package/dist/database/entities/password.entity.js +36 -0
- package/dist/database/entities/password.entity.js.map +1 -0
- package/dist/database/entities/refresh-token.entity.d.ts +9 -0
- package/dist/database/entities/refresh-token.entity.js +53 -0
- package/dist/database/entities/refresh-token.entity.js.map +1 -0
- package/dist/database/entities/session.entity.d.ts +20 -0
- package/dist/database/entities/session.entity.js +87 -0
- package/dist/database/entities/session.entity.js.map +1 -0
- package/dist/database/entities/settings.entity.d.ts +7 -0
- package/dist/database/entities/settings.entity.js +41 -0
- package/dist/database/entities/settings.entity.js.map +1 -0
- package/dist/database/entities/sign-in-challenge.entity.d.ts +23 -0
- package/dist/database/entities/sign-in-challenge.entity.js +80 -0
- package/dist/database/entities/sign-in-challenge.entity.js.map +1 -0
- package/dist/database/entities/signing-key.entity.d.ts +11 -0
- package/dist/database/entities/signing-key.entity.js +54 -0
- package/dist/database/entities/signing-key.entity.js.map +1 -0
- package/dist/database/entities/social-account.entity.d.ts +13 -0
- package/dist/database/entities/social-account.entity.js +54 -0
- package/dist/database/entities/social-account.entity.js.map +1 -0
- package/dist/database/entities/two-factor-secret.entity.d.ts +10 -0
- package/dist/database/entities/two-factor-secret.entity.js +48 -0
- package/dist/database/entities/two-factor-secret.entity.js.map +1 -0
- package/dist/database/entities/user.entity.d.ts +34 -0
- package/dist/database/entities/user.entity.js +129 -0
- package/dist/database/entities/user.entity.js.map +1 -0
- package/dist/database/entities/webhook-delivery.entity.d.ts +17 -0
- package/dist/database/entities/webhook-delivery.entity.js +79 -0
- package/dist/database/entities/webhook-delivery.entity.js.map +1 -0
- package/dist/database/entities/webhook.entity.d.ts +12 -0
- package/dist/database/entities/webhook.entity.js +58 -0
- package/dist/database/entities/webhook.entity.js.map +1 -0
- package/dist/database/typeorm-row.d.ts +21 -0
- package/dist/database/typeorm-row.js +29 -0
- package/dist/database/typeorm-row.js.map +1 -0
- package/dist/features/account/account.controller.d.ts +259 -0
- package/dist/features/account/account.controller.js +372 -0
- package/dist/features/account/account.controller.js.map +1 -0
- package/dist/features/account/account.dto.d.ts +16 -0
- package/dist/features/account/account.dto.js +61 -0
- package/dist/features/account/account.dto.js.map +1 -0
- package/dist/features/account/data-export.service.d.ts +85 -0
- package/dist/features/account/data-export.service.js +125 -0
- package/dist/features/account/data-export.service.js.map +1 -0
- package/dist/features/account/health.service.d.ts +30 -0
- package/dist/features/account/health.service.js +59 -0
- package/dist/features/account/health.service.js.map +1 -0
- package/dist/features/admin/admin.controller.d.ts +382 -0
- package/dist/features/admin/admin.controller.js +623 -0
- package/dist/features/admin/admin.controller.js.map +1 -0
- package/dist/features/admin/admin.dto.d.ts +61 -0
- package/dist/features/admin/admin.dto.js +253 -0
- package/dist/features/admin/admin.dto.js.map +1 -0
- package/dist/features/admin/admin.service.d.ts +142 -0
- package/dist/features/admin/admin.service.js +227 -0
- package/dist/features/admin/admin.service.js.map +1 -0
- package/dist/features/api-keys/api-keys.service.d.ts +67 -0
- package/dist/features/api-keys/api-keys.service.js +144 -0
- package/dist/features/api-keys/api-keys.service.js.map +1 -0
- package/dist/features/email-change/email-change.controller.d.ts +38 -0
- package/dist/features/email-change/email-change.controller.js +85 -0
- package/dist/features/email-change/email-change.controller.js.map +1 -0
- package/dist/features/email-change/email-change.dto.d.ts +10 -0
- package/dist/features/email-change/email-change.dto.js +43 -0
- package/dist/features/email-change/email-change.dto.js.map +1 -0
- package/dist/features/email-change/email-change.service.d.ts +74 -0
- package/dist/features/email-change/email-change.service.js +179 -0
- package/dist/features/email-change/email-change.service.js.map +1 -0
- package/dist/features/email-links/email-verification.service.d.ts +46 -0
- package/dist/features/email-links/email-verification.service.js +94 -0
- package/dist/features/email-links/email-verification.service.js.map +1 -0
- package/dist/features/email-links/link-tokens.service.d.ts +44 -0
- package/dist/features/email-links/link-tokens.service.js +122 -0
- package/dist/features/email-links/link-tokens.service.js.map +1 -0
- package/dist/features/events/auth-events.service.d.ts +52 -0
- package/dist/features/events/auth-events.service.js +117 -0
- package/dist/features/events/auth-events.service.js.map +1 -0
- package/dist/features/maintenance/data-retention.service.d.ts +60 -0
- package/dist/features/maintenance/data-retention.service.js +182 -0
- package/dist/features/maintenance/data-retention.service.js.map +1 -0
- package/dist/features/notifications/notifications.service.d.ts +40 -0
- package/dist/features/notifications/notifications.service.js +94 -0
- package/dist/features/notifications/notifications.service.js.map +1 -0
- package/dist/features/one-time-codes/one-time-codes.service.d.ts +40 -0
- package/dist/features/one-time-codes/one-time-codes.service.js +102 -0
- package/dist/features/one-time-codes/one-time-codes.service.js.map +1 -0
- package/dist/features/organizations/organizations.controller.d.ts +220 -0
- package/dist/features/organizations/organizations.controller.js +337 -0
- package/dist/features/organizations/organizations.controller.js.map +1 -0
- package/dist/features/organizations/organizations.dto.d.ts +31 -0
- package/dist/features/organizations/organizations.dto.js +100 -0
- package/dist/features/organizations/organizations.dto.js.map +1 -0
- package/dist/features/organizations/organizations.service.d.ts +274 -0
- package/dist/features/organizations/organizations.service.js +481 -0
- package/dist/features/organizations/organizations.service.js.map +1 -0
- package/dist/features/passkeys/passkeys.controller.d.ts +92 -0
- package/dist/features/passkeys/passkeys.controller.js +183 -0
- package/dist/features/passkeys/passkeys.controller.js.map +1 -0
- package/dist/features/passkeys/passkeys.dto.d.ts +13 -0
- package/dist/features/passkeys/passkeys.dto.js +50 -0
- package/dist/features/passkeys/passkeys.dto.js.map +1 -0
- package/dist/features/passkeys/passkeys.service.d.ts +159 -0
- package/dist/features/passkeys/passkeys.service.js +350 -0
- package/dist/features/passkeys/passkeys.service.js.map +1 -0
- package/dist/features/passwordless/passwordless-auth.service.d.ts +152 -0
- package/dist/features/passwordless/passwordless-auth.service.js +304 -0
- package/dist/features/passwordless/passwordless-auth.service.js.map +1 -0
- package/dist/features/passwordless/passwordless.controller.d.ts +75 -0
- package/dist/features/passwordless/passwordless.controller.js +163 -0
- package/dist/features/passwordless/passwordless.controller.js.map +1 -0
- package/dist/features/passwordless/passwordless.dto.d.ts +29 -0
- package/dist/features/passwordless/passwordless.dto.js +101 -0
- package/dist/features/passwordless/passwordless.dto.js.map +1 -0
- package/dist/features/passwords/password-auth.service.d.ts +154 -0
- package/dist/features/passwords/password-auth.service.js +317 -0
- package/dist/features/passwords/password-auth.service.js.map +1 -0
- package/dist/features/passwords/password-policy.service.d.ts +63 -0
- package/dist/features/passwords/password-policy.service.js +175 -0
- package/dist/features/passwords/password-policy.service.js.map +1 -0
- package/dist/features/passwords/password.controller.d.ts +95 -0
- package/dist/features/passwords/password.controller.js +193 -0
- package/dist/features/passwords/password.controller.js.map +1 -0
- package/dist/features/passwords/password.dto.d.ts +36 -0
- package/dist/features/passwords/password.dto.js +140 -0
- package/dist/features/passwords/password.dto.js.map +1 -0
- package/dist/features/sessions/session.service.d.ts +132 -0
- package/dist/features/sessions/session.service.js +308 -0
- package/dist/features/sessions/session.service.js.map +1 -0
- package/dist/features/sessions/session.types.d.ts +34 -0
- package/dist/features/sessions/session.types.js +3 -0
- package/dist/features/sessions/session.types.js.map +1 -0
- package/dist/features/settings/settings.defaults.d.ts +2 -0
- package/dist/features/settings/settings.defaults.js +7 -0
- package/dist/features/settings/settings.defaults.js.map +1 -0
- package/dist/features/settings/settings.service.d.ts +44 -0
- package/dist/features/settings/settings.service.js +112 -0
- package/dist/features/settings/settings.service.js.map +1 -0
- package/dist/features/settings/settings.types.d.ts +133 -0
- package/dist/features/settings/settings.types.js +3 -0
- package/dist/features/settings/settings.types.js.map +1 -0
- package/dist/features/settings/settings.validation.d.ts +33 -0
- package/dist/features/settings/settings.validation.js +614 -0
- package/dist/features/settings/settings.validation.js.map +1 -0
- package/dist/features/sign-in/sign-in-challenges.service.d.ts +54 -0
- package/dist/features/sign-in/sign-in-challenges.service.js +104 -0
- package/dist/features/sign-in/sign-in-challenges.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.service.d.ts +127 -0
- package/dist/features/sign-in/sign-in.service.js +248 -0
- package/dist/features/sign-in/sign-in.service.js.map +1 -0
- package/dist/features/sign-in/sign-in.types.d.ts +22 -0
- package/dist/features/sign-in/sign-in.types.js +3 -0
- package/dist/features/sign-in/sign-in.types.js.map +1 -0
- package/dist/features/signing-keys/jwks.controller.d.ts +17 -0
- package/dist/features/signing-keys/jwks.controller.js +51 -0
- package/dist/features/signing-keys/jwks.controller.js.map +1 -0
- package/dist/features/signing-keys/signing-keys.service.d.ts +67 -0
- package/dist/features/signing-keys/signing-keys.service.js +142 -0
- package/dist/features/signing-keys/signing-keys.service.js.map +1 -0
- package/dist/features/social/social-auth.service.d.ts +100 -0
- package/dist/features/social/social-auth.service.js +232 -0
- package/dist/features/social/social-auth.service.js.map +1 -0
- package/dist/features/social/social-providers.service.d.ts +97 -0
- package/dist/features/social/social-providers.service.js +214 -0
- package/dist/features/social/social-providers.service.js.map +1 -0
- package/dist/features/social/social.controller.d.ts +54 -0
- package/dist/features/social/social.controller.js +124 -0
- package/dist/features/social/social.controller.js.map +1 -0
- package/dist/features/social/social.dto.d.ts +11 -0
- package/dist/features/social/social.dto.js +38 -0
- package/dist/features/social/social.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.controller.d.ts +84 -0
- package/dist/features/two-factor/two-factor.controller.js +174 -0
- package/dist/features/two-factor/two-factor.controller.js.map +1 -0
- package/dist/features/two-factor/two-factor.dto.d.ts +10 -0
- package/dist/features/two-factor/two-factor.dto.js +37 -0
- package/dist/features/two-factor/two-factor.dto.js.map +1 -0
- package/dist/features/two-factor/two-factor.service.d.ts +171 -0
- package/dist/features/two-factor/two-factor.service.js +348 -0
- package/dist/features/two-factor/two-factor.service.js.map +1 -0
- package/dist/features/users/sign-in-methods.service.d.ts +40 -0
- package/dist/features/users/sign-in-methods.service.js +81 -0
- package/dist/features/users/sign-in-methods.service.js.map +1 -0
- package/dist/features/users/sign-up-rules.d.ts +12 -0
- package/dist/features/users/sign-up-rules.js +29 -0
- package/dist/features/users/sign-up-rules.js.map +1 -0
- package/dist/features/users/users.service.d.ts +246 -0
- package/dist/features/users/users.service.js +509 -0
- package/dist/features/users/users.service.js.map +1 -0
- package/dist/features/users/users.types.d.ts +24 -0
- package/dist/features/users/users.types.js +3 -0
- package/dist/features/users/users.types.js.map +1 -0
- package/dist/features/webhooks/webhook-delivery.worker.d.ts +55 -0
- package/dist/features/webhooks/webhook-delivery.worker.js +175 -0
- package/dist/features/webhooks/webhook-delivery.worker.js.map +1 -0
- package/dist/features/webhooks/webhook-signature.d.ts +28 -0
- package/dist/features/webhooks/webhook-signature.js +85 -0
- package/dist/features/webhooks/webhook-signature.js.map +1 -0
- package/dist/features/webhooks/webhooks.service.d.ts +144 -0
- package/dist/features/webhooks/webhooks.service.js +238 -0
- package/dist/features/webhooks/webhooks.service.js.map +1 -0
- package/dist/guards/auth.decorators.d.ts +65 -0
- package/dist/guards/auth.decorators.js +68 -0
- package/dist/guards/auth.decorators.js.map +1 -0
- package/dist/guards/auth.guard.d.ts +47 -0
- package/dist/guards/auth.guard.js +132 -0
- package/dist/guards/auth.guard.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/console-email-sender.d.ts +15 -0
- package/dist/integrations/console-email-sender.js +26 -0
- package/dist/integrations/console-email-sender.js.map +1 -0
- package/dist/integrations/msg91-sms-sender.d.ts +28 -0
- package/dist/integrations/msg91-sms-sender.js +46 -0
- package/dist/integrations/msg91-sms-sender.js.map +1 -0
- package/docs/README.md +39 -0
- package/docs/admin-api-keys-webhooks.md +147 -0
- package/docs/api-reference.md +175 -0
- package/docs/architecture.md +119 -0
- package/docs/client-integration.md +192 -0
- package/docs/code-walkthrough.md +273 -0
- package/docs/configuration.md +229 -0
- package/docs/endpoints/README.md +151 -0
- package/docs/endpoints/account.md +363 -0
- package/docs/endpoints/admin.md +422 -0
- package/docs/endpoints/email-password.md +261 -0
- package/docs/endpoints/organizations.md +192 -0
- package/docs/endpoints/passkeys.md +195 -0
- package/docs/endpoints/passwordless.md +214 -0
- package/docs/endpoints/social.md +116 -0
- package/docs/endpoints/two-factor.md +146 -0
- package/docs/error-codes.md +100 -0
- package/docs/events.md +83 -0
- package/docs/getting-started.md +139 -0
- package/docs/manual-testing.md +215 -0
- package/docs/organizations.md +86 -0
- package/docs/production-checklist.md +60 -0
- package/docs/protecting-routes.md +147 -0
- package/docs/security.md +61 -0
- package/docs/sign-in-flows.md +294 -0
- package/package.json +92 -4
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.TokenInput = exports.ChangePasswordInput = exports.ResetPasswordInput = exports.EmailOnlyInput = exports.SignInWithPasswordInput = exports.RegisterInput = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const constants_1 = require("../../constants.js");
|
|
15
|
+
/*
|
|
16
|
+
* Request bodies. These check the SHAPE of the input (types and lengths); the services check the
|
|
17
|
+
* MEANING (valid email, password rules, settings). Unknown fields are rejected by the validation pipe.
|
|
18
|
+
*/
|
|
19
|
+
/** POST /auth/register */
|
|
20
|
+
class RegisterInput {
|
|
21
|
+
email;
|
|
22
|
+
password;
|
|
23
|
+
firstName;
|
|
24
|
+
lastName;
|
|
25
|
+
/** International format, e.g. +919876543210. */
|
|
26
|
+
phoneNumber;
|
|
27
|
+
acceptTerms;
|
|
28
|
+
acceptPrivacyPolicy;
|
|
29
|
+
}
|
|
30
|
+
exports.RegisterInput = RegisterInput;
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_validator_1.IsString)(),
|
|
33
|
+
(0, class_validator_1.MaxLength)(constants_1.EMAIL_MAX_LENGTH),
|
|
34
|
+
__metadata("design:type", String)
|
|
35
|
+
], RegisterInput.prototype, "email", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, class_validator_1.IsString)(),
|
|
38
|
+
(0, class_validator_1.MaxLength)(constants_1.PASSWORD_MAX_LENGTH),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], RegisterInput.prototype, "password", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, class_validator_1.IsOptional)(),
|
|
43
|
+
(0, class_validator_1.IsString)(),
|
|
44
|
+
(0, class_validator_1.MaxLength)(constants_1.DISPLAY_NAME_MAX_LENGTH),
|
|
45
|
+
__metadata("design:type", String)
|
|
46
|
+
], RegisterInput.prototype, "firstName", void 0);
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, class_validator_1.IsOptional)(),
|
|
49
|
+
(0, class_validator_1.IsString)(),
|
|
50
|
+
(0, class_validator_1.MaxLength)(constants_1.DISPLAY_NAME_MAX_LENGTH),
|
|
51
|
+
__metadata("design:type", String)
|
|
52
|
+
], RegisterInput.prototype, "lastName", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
(0, class_validator_1.IsOptional)(),
|
|
55
|
+
(0, class_validator_1.IsString)(),
|
|
56
|
+
(0, class_validator_1.MaxLength)(constants_1.PHONE_NUMBER_INPUT_MAX_LENGTH),
|
|
57
|
+
__metadata("design:type", String)
|
|
58
|
+
], RegisterInput.prototype, "phoneNumber", void 0);
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, class_validator_1.IsOptional)(),
|
|
61
|
+
(0, class_validator_1.IsBoolean)(),
|
|
62
|
+
__metadata("design:type", Boolean)
|
|
63
|
+
], RegisterInput.prototype, "acceptTerms", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, class_validator_1.IsOptional)(),
|
|
66
|
+
(0, class_validator_1.IsBoolean)(),
|
|
67
|
+
__metadata("design:type", Boolean)
|
|
68
|
+
], RegisterInput.prototype, "acceptPrivacyPolicy", void 0);
|
|
69
|
+
/** POST /auth/login */
|
|
70
|
+
class SignInWithPasswordInput {
|
|
71
|
+
email;
|
|
72
|
+
password;
|
|
73
|
+
}
|
|
74
|
+
exports.SignInWithPasswordInput = SignInWithPasswordInput;
|
|
75
|
+
__decorate([
|
|
76
|
+
(0, class_validator_1.IsString)(),
|
|
77
|
+
(0, class_validator_1.MaxLength)(constants_1.EMAIL_MAX_LENGTH),
|
|
78
|
+
__metadata("design:type", String)
|
|
79
|
+
], SignInWithPasswordInput.prototype, "email", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, class_validator_1.IsString)(),
|
|
82
|
+
(0, class_validator_1.MaxLength)(constants_1.PASSWORD_MAX_LENGTH),
|
|
83
|
+
__metadata("design:type", String)
|
|
84
|
+
], SignInWithPasswordInput.prototype, "password", void 0);
|
|
85
|
+
/** POST /auth/password/forgot, /auth/email/send-verification, /auth/email/send-otp, magic link */
|
|
86
|
+
class EmailOnlyInput {
|
|
87
|
+
email;
|
|
88
|
+
}
|
|
89
|
+
exports.EmailOnlyInput = EmailOnlyInput;
|
|
90
|
+
__decorate([
|
|
91
|
+
(0, class_validator_1.IsString)(),
|
|
92
|
+
(0, class_validator_1.MaxLength)(constants_1.EMAIL_MAX_LENGTH),
|
|
93
|
+
__metadata("design:type", String)
|
|
94
|
+
], EmailOnlyInput.prototype, "email", void 0);
|
|
95
|
+
/** POST /auth/password/reset */
|
|
96
|
+
class ResetPasswordInput {
|
|
97
|
+
/** The token from the reset link. */
|
|
98
|
+
token;
|
|
99
|
+
newPassword;
|
|
100
|
+
}
|
|
101
|
+
exports.ResetPasswordInput = ResetPasswordInput;
|
|
102
|
+
__decorate([
|
|
103
|
+
(0, class_validator_1.IsString)(),
|
|
104
|
+
(0, class_validator_1.MaxLength)(constants_1.RANDOM_TOKEN_INPUT_MAX_LENGTH),
|
|
105
|
+
__metadata("design:type", String)
|
|
106
|
+
], ResetPasswordInput.prototype, "token", void 0);
|
|
107
|
+
__decorate([
|
|
108
|
+
(0, class_validator_1.IsString)(),
|
|
109
|
+
(0, class_validator_1.MaxLength)(constants_1.PASSWORD_MAX_LENGTH),
|
|
110
|
+
__metadata("design:type", String)
|
|
111
|
+
], ResetPasswordInput.prototype, "newPassword", void 0);
|
|
112
|
+
/** POST /auth/password/change */
|
|
113
|
+
class ChangePasswordInput {
|
|
114
|
+
/** Leave out only if the account has no password yet (signed up with Google etc.). */
|
|
115
|
+
currentPassword;
|
|
116
|
+
newPassword;
|
|
117
|
+
}
|
|
118
|
+
exports.ChangePasswordInput = ChangePasswordInput;
|
|
119
|
+
__decorate([
|
|
120
|
+
(0, class_validator_1.IsOptional)(),
|
|
121
|
+
(0, class_validator_1.IsString)(),
|
|
122
|
+
(0, class_validator_1.MaxLength)(constants_1.PASSWORD_MAX_LENGTH),
|
|
123
|
+
__metadata("design:type", String)
|
|
124
|
+
], ChangePasswordInput.prototype, "currentPassword", void 0);
|
|
125
|
+
__decorate([
|
|
126
|
+
(0, class_validator_1.IsString)(),
|
|
127
|
+
(0, class_validator_1.MaxLength)(constants_1.PASSWORD_MAX_LENGTH),
|
|
128
|
+
__metadata("design:type", String)
|
|
129
|
+
], ChangePasswordInput.prototype, "newPassword", void 0);
|
|
130
|
+
/** Any endpoint that receives a single token: verify email, magic link, refresh, reactivate... */
|
|
131
|
+
class TokenInput {
|
|
132
|
+
token;
|
|
133
|
+
}
|
|
134
|
+
exports.TokenInput = TokenInput;
|
|
135
|
+
__decorate([
|
|
136
|
+
(0, class_validator_1.IsString)(),
|
|
137
|
+
(0, class_validator_1.MaxLength)(constants_1.RANDOM_TOKEN_INPUT_MAX_LENGTH),
|
|
138
|
+
__metadata("design:type", String)
|
|
139
|
+
], TokenInput.prototype, "token", void 0);
|
|
140
|
+
//# sourceMappingURL=password.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.dto.js","sourceRoot":"","sources":["../../../src/features/passwords/password.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA6E;AAC7E,2CAMqB;AAErB;;;GAGG;AAEH,0BAA0B;AAC1B,MAAa,aAAa;IAExB,KAAK,CAAS;IAGd,QAAQ,CAAS;IAGjB,SAAS,CAAU;IAGnB,QAAQ,CAAU;IAElB,gDAAgD;IAEhD,WAAW,CAAU;IAGrB,WAAW,CAAW;IAGtB,mBAAmB,CAAW;CAC/B;AAtBD,sCAsBC;AApBC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,4BAAgB,CAAC;;4CAC1B;AAGd;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,+BAAmB,CAAC;;+CAC1B;AAGjB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,mCAAuB,CAAC;;gDAC1C;AAGnB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,mCAAuB,CAAC;;+CAC3C;AAIlB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;kDAC9C;AAGrB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,2BAAS,GAAE;;kDACJ;AAGtB;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,2BAAS,GAAE;;0DACI;AAGhC,uBAAuB;AACvB,MAAa,uBAAuB;IAElC,KAAK,CAAS;IAGd,QAAQ,CAAS;CAClB;AAND,0DAMC;AAJC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,4BAAgB,CAAC;;sDAC1B;AAGd;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,+BAAmB,CAAC;;yDAC1B;AAGnB,kGAAkG;AAClG,MAAa,cAAc;IAEzB,KAAK,CAAS;CACf;AAHD,wCAGC;AADC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,4BAAgB,CAAC;;6CAC1B;AAGhB,gCAAgC;AAChC,MAAa,kBAAkB;IAC7B,qCAAqC;IAErC,KAAK,CAAS;IAGd,WAAW,CAAS;CACrB;AAPD,gDAOC;AAJC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;iDACvC;AAGd;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,+BAAmB,CAAC;;uDACvB;AAGtB,iCAAiC;AACjC,MAAa,mBAAmB;IAC9B,sFAAsF;IAEtF,eAAe,CAAU;IAGzB,WAAW,CAAS;CACrB;AAPD,kDAOC;AAJC;IADC,IAAA,4BAAU,GAAE;IAAE,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,+BAAmB,CAAC;;4DAChC;AAGzB;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,+BAAmB,CAAC;;wDACvB;AAGtB,kGAAkG;AAClG,MAAa,UAAU;IAErB,KAAK,CAAS;CACf;AAHD,gCAGC;AADC;IADC,IAAA,0BAAQ,GAAE;IAAE,IAAA,2BAAS,EAAC,yCAA6B,CAAC;;yCACvC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AuthOptions } from '../../auth-options.js';
|
|
2
|
+
import { RequestContext } from '../../common/request-context.js';
|
|
3
|
+
import { type SessionEndReason } from '../../constants.js';
|
|
4
|
+
import { SessionEntity, UserEntity } from '../../database/entities/index.js';
|
|
5
|
+
import { AuthEventsService } from '../events/auth-events.service.js';
|
|
6
|
+
import { AuthSettings } from '../settings/settings.types.js';
|
|
7
|
+
import { SigningKeysService } from '../signing-keys/signing-keys.service.js';
|
|
8
|
+
import { AccessTokenClaims, SignInMethod, TokenSet } from './session.types';
|
|
9
|
+
/**
|
|
10
|
+
* Sessions (one per signed-in device) and the tokens that belong to them.
|
|
11
|
+
*
|
|
12
|
+
* - Access token: a signed JWT that lives a few minutes. Your API checks it on every request.
|
|
13
|
+
* - Refresh token: a random string that works ONCE to get a new pair of tokens. If an already-used
|
|
14
|
+
* refresh token comes back, someone copied it, so we end that session to protect the user.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SessionService {
|
|
17
|
+
private readonly signingKeys;
|
|
18
|
+
private readonly events;
|
|
19
|
+
private readonly logger;
|
|
20
|
+
private readonly database;
|
|
21
|
+
/** Token "iss" and "aud": your API's URL. */
|
|
22
|
+
readonly issuer: string;
|
|
23
|
+
/** Short cache of "is this session still allowed?" answers, so the database isn't hit on every request. */
|
|
24
|
+
private readonly sessionCheckCache;
|
|
25
|
+
constructor(options: AuthOptions, signingKeys: SigningKeysService, events: AuthEventsService);
|
|
26
|
+
/**
|
|
27
|
+
* Starts a session for a user who has just proven who they are, and returns their first tokens.
|
|
28
|
+
*
|
|
29
|
+
* @param user - The user signing in.
|
|
30
|
+
* @param signInMethod - How they signed in (goes into the token's "amr" claim).
|
|
31
|
+
* @param usedTwoFactor - Whether a second factor was used.
|
|
32
|
+
* @param request - The device's IP and user agent, shown in the user's device list.
|
|
33
|
+
* @param settings - The current settings (session and token lifetimes).
|
|
34
|
+
* @returns The access token, refresh token and session id.
|
|
35
|
+
*/
|
|
36
|
+
startSession(user: UserEntity, signInMethod: SignInMethod, usedTwoFactor: boolean, request: RequestContext, settings: AuthSettings): Promise<TokenSet>;
|
|
37
|
+
/**
|
|
38
|
+
* Swaps a refresh token for a new access token and a new refresh token.
|
|
39
|
+
* Each refresh token works exactly once; a second use ends the whole session.
|
|
40
|
+
*
|
|
41
|
+
* @param refreshToken - The "rt_..." token the client sent.
|
|
42
|
+
* @param request - Who is asking (for the audit log if the token was reused).
|
|
43
|
+
* @param settings - The current settings.
|
|
44
|
+
* @returns A new set of tokens for the same session.
|
|
45
|
+
* @throws AuthError INVALID_TOKEN when the token is unknown, used, expired, its session has
|
|
46
|
+
* ended, or the account is no longer active.
|
|
47
|
+
*/
|
|
48
|
+
refreshSession(refreshToken: unknown, request: RequestContext, settings: AuthSettings): Promise<TokenSet>;
|
|
49
|
+
/**
|
|
50
|
+
* Checks an access token's signature, issuer, audience and expiry.
|
|
51
|
+
* This does not check whether the session was ended since; see `isSessionStillAllowed`.
|
|
52
|
+
*
|
|
53
|
+
* @param accessToken - The token from the Authorization header.
|
|
54
|
+
* @returns The token's claims (user id, session id, roles...).
|
|
55
|
+
* @throws AuthError INVALID_TOKEN when any check fails.
|
|
56
|
+
*/
|
|
57
|
+
verifyAccessToken(accessToken: string): Promise<AccessTokenClaims>;
|
|
58
|
+
/**
|
|
59
|
+
* Checks that the session has not been ended and its user is ACTIVE.
|
|
60
|
+
* Answers are cached for a few seconds, so signing out or suspending takes effect almost at once
|
|
61
|
+
* without a database query on every request.
|
|
62
|
+
*
|
|
63
|
+
* @param sessionId - The "sid" claim from the access token.
|
|
64
|
+
* @param userId - The "sub" claim from the access token.
|
|
65
|
+
* @returns True when requests from this session should still be accepted.
|
|
66
|
+
*/
|
|
67
|
+
isSessionStillAllowed(sessionId: string, userId: string): Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Ends one session.
|
|
70
|
+
*
|
|
71
|
+
* @param sessionId - The session to end.
|
|
72
|
+
* @param reason - Why it ended (stored, and shown in the audit log).
|
|
73
|
+
* @param userId - When given, the session is only ended if it belongs to this user.
|
|
74
|
+
* @returns False if nothing was ended (unknown, already ended, or someone else's session).
|
|
75
|
+
*/
|
|
76
|
+
revokeSession(sessionId: string, reason: SessionEndReason, userId?: string): Promise<boolean>;
|
|
77
|
+
/**
|
|
78
|
+
* Ends every session of a user, e.g. after a password change.
|
|
79
|
+
*
|
|
80
|
+
* @param userId - The user to sign out.
|
|
81
|
+
* @param reason - Why the sessions ended.
|
|
82
|
+
* @param keepSessionId - When given, this session (the device making the request) stays signed in.
|
|
83
|
+
* @returns How many sessions were ended.
|
|
84
|
+
*/
|
|
85
|
+
revokeAllSessions(userId: string, reason: SessionEndReason, keepSessionId?: string): Promise<number>;
|
|
86
|
+
/**
|
|
87
|
+
* Lists the user's signed-in devices, most recently used first.
|
|
88
|
+
*
|
|
89
|
+
* @param userId - The user.
|
|
90
|
+
* @returns The sessions that have not ended or expired.
|
|
91
|
+
*/
|
|
92
|
+
listActiveSessions(userId: string): Promise<SessionEntity[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Switches the organization a device is working in, and returns a fresh access token that carries it
|
|
95
|
+
* (in the "org_id" and "org_role" claims).
|
|
96
|
+
*
|
|
97
|
+
* @param sessionId - The device's session.
|
|
98
|
+
* @param organizationId - The organization to switch to, or null for none.
|
|
99
|
+
* @param settings - The current settings.
|
|
100
|
+
* @returns A new access token and its lifetime in seconds.
|
|
101
|
+
*/
|
|
102
|
+
switchActiveOrganization(sessionId: string, organizationId: string | null, settings: AuthSettings): Promise<{
|
|
103
|
+
accessToken: string;
|
|
104
|
+
expiresIn: number;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Creates a new access token and a new refresh token for a session.
|
|
108
|
+
*
|
|
109
|
+
* @param user - The session's user.
|
|
110
|
+
* @param session - The session the tokens belong to.
|
|
111
|
+
* @param settings - The current settings (token lifetimes).
|
|
112
|
+
* @returns The full token set to send to the client.
|
|
113
|
+
*/
|
|
114
|
+
private issueTokens;
|
|
115
|
+
/**
|
|
116
|
+
* Signs an access token with the user's roles, how they signed in, and the active organization.
|
|
117
|
+
*
|
|
118
|
+
* @param user - The session's user.
|
|
119
|
+
* @param session - The session the token belongs to.
|
|
120
|
+
* @param settings - The current settings (access token lifetime).
|
|
121
|
+
* @returns The signed token and its lifetime in seconds.
|
|
122
|
+
*/
|
|
123
|
+
private createAccessToken;
|
|
124
|
+
/**
|
|
125
|
+
* An already-used refresh token came back: it was copied. End the session; the real user simply
|
|
126
|
+
* signs in again. Does nothing if the token was never ours.
|
|
127
|
+
*
|
|
128
|
+
* @param tokenHash - The hash of the token that was sent.
|
|
129
|
+
* @param request - Who sent it (for the audit log).
|
|
130
|
+
*/
|
|
131
|
+
private handleRefreshTokenReuse;
|
|
132
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SessionService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const node_crypto_1 = require("node:crypto");
|
|
18
|
+
const typeorm_1 = require("typeorm");
|
|
19
|
+
const auth_error_1 = require("../../common/auth-error.js");
|
|
20
|
+
const jwt_1 = require("../../common/crypto/jwt.js");
|
|
21
|
+
const random_secrets_1 = require("../../common/crypto/random-secrets.js");
|
|
22
|
+
const constants_1 = require("../../constants.js");
|
|
23
|
+
const entities_1 = require("../../database/entities/index.js");
|
|
24
|
+
const auth_events_service_1 = require("../events/auth-events.service.js");
|
|
25
|
+
const signing_keys_service_1 = require("../signing-keys/signing-keys.service.js");
|
|
26
|
+
const time_1 = require("../../common/time.js");
|
|
27
|
+
/**
|
|
28
|
+
* Sessions (one per signed-in device) and the tokens that belong to them.
|
|
29
|
+
*
|
|
30
|
+
* - Access token: a signed JWT that lives a few minutes. Your API checks it on every request.
|
|
31
|
+
* - Refresh token: a random string that works ONCE to get a new pair of tokens. If an already-used
|
|
32
|
+
* refresh token comes back, someone copied it, so we end that session to protect the user.
|
|
33
|
+
*/
|
|
34
|
+
let SessionService = class SessionService {
|
|
35
|
+
signingKeys;
|
|
36
|
+
events;
|
|
37
|
+
logger = new common_1.Logger(constants_1.LOG_CONTEXT.sessions);
|
|
38
|
+
database;
|
|
39
|
+
/** Token "iss" and "aud": your API's URL. */
|
|
40
|
+
issuer;
|
|
41
|
+
/** Short cache of "is this session still allowed?" answers, so the database isn't hit on every request. */
|
|
42
|
+
sessionCheckCache = new Map();
|
|
43
|
+
constructor(options, signingKeys, events) {
|
|
44
|
+
this.signingKeys = signingKeys;
|
|
45
|
+
this.events = events;
|
|
46
|
+
this.database = options.dataSource;
|
|
47
|
+
this.issuer = options.issuer.replace(constants_1.TRAILING_SLASHES_PATTERN, '');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Starts a session for a user who has just proven who they are, and returns their first tokens.
|
|
51
|
+
*
|
|
52
|
+
* @param user - The user signing in.
|
|
53
|
+
* @param signInMethod - How they signed in (goes into the token's "amr" claim).
|
|
54
|
+
* @param usedTwoFactor - Whether a second factor was used.
|
|
55
|
+
* @param request - The device's IP and user agent, shown in the user's device list.
|
|
56
|
+
* @param settings - The current settings (session and token lifetimes).
|
|
57
|
+
* @returns The access token, refresh token and session id.
|
|
58
|
+
*/
|
|
59
|
+
async startSession(user, signInMethod, usedTwoFactor, request, settings) {
|
|
60
|
+
const now = new Date();
|
|
61
|
+
const session = await this.database.getRepository(entities_1.SessionEntity).save({
|
|
62
|
+
userId: user.id,
|
|
63
|
+
signInMethod,
|
|
64
|
+
usedTwoFactor,
|
|
65
|
+
ipAddress: request.ipAddress,
|
|
66
|
+
userAgent: request.userAgent,
|
|
67
|
+
lastUsedAt: now,
|
|
68
|
+
expiresAt: new Date(now.getTime() + settings.tokens.sessionDays * constants_1.DAY_IN_SECONDS * constants_1.SECOND_IN_MILLISECONDS),
|
|
69
|
+
});
|
|
70
|
+
return this.issueTokens(user, session, settings);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Swaps a refresh token for a new access token and a new refresh token.
|
|
74
|
+
* Each refresh token works exactly once; a second use ends the whole session.
|
|
75
|
+
*
|
|
76
|
+
* @param refreshToken - The "rt_..." token the client sent.
|
|
77
|
+
* @param request - Who is asking (for the audit log if the token was reused).
|
|
78
|
+
* @param settings - The current settings.
|
|
79
|
+
* @returns A new set of tokens for the same session.
|
|
80
|
+
* @throws AuthError INVALID_TOKEN when the token is unknown, used, expired, its session has
|
|
81
|
+
* ended, or the account is no longer active.
|
|
82
|
+
*/
|
|
83
|
+
async refreshSession(refreshToken, request, settings) {
|
|
84
|
+
if (!(0, random_secrets_1.hasRandomTokenFormat)(refreshToken, constants_1.TOKEN_PREFIX.refreshToken))
|
|
85
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidRefreshToken);
|
|
86
|
+
const tokenHash = (0, random_secrets_1.sha256Hex)(refreshToken);
|
|
87
|
+
// Mark the token used in a single UPDATE: if two requests race, only one gets a row back.
|
|
88
|
+
const markAsUsed = await this.database
|
|
89
|
+
.createQueryBuilder()
|
|
90
|
+
.update(entities_1.RefreshTokenEntity)
|
|
91
|
+
.set({ usedAt: () => 'now()' })
|
|
92
|
+
.where('token_hash = :tokenHash AND used_at IS NULL AND expires_at > now()', { tokenHash })
|
|
93
|
+
// returning() takes entity property names; the raw rows use column names (session_id).
|
|
94
|
+
.returning(['sessionId'])
|
|
95
|
+
.execute();
|
|
96
|
+
const sessionId = markAsUsed.raw[0]?.session_id;
|
|
97
|
+
if (!sessionId) {
|
|
98
|
+
await this.handleRefreshTokenReuse(tokenHash, request);
|
|
99
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidRefreshToken);
|
|
100
|
+
}
|
|
101
|
+
const session = await this.database.getRepository(entities_1.SessionEntity).findOne({
|
|
102
|
+
where: { id: sessionId, revokedAt: (0, typeorm_1.IsNull)(), expiresAt: (0, typeorm_1.MoreThan)(new Date()) },
|
|
103
|
+
});
|
|
104
|
+
if (!session)
|
|
105
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidRefreshToken);
|
|
106
|
+
// The account may have been suspended or deactivated since the last refresh.
|
|
107
|
+
const user = await this.database.getRepository(entities_1.UserEntity).findOne({ where: { id: session.userId } });
|
|
108
|
+
if (!user || user.status !== constants_1.ACCOUNT_STATUS.active) {
|
|
109
|
+
await this.revokeSession(session.id, constants_1.SESSION_END_REASON.accountNotActive);
|
|
110
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidRefreshToken);
|
|
111
|
+
}
|
|
112
|
+
await this.database.getRepository(entities_1.SessionEntity).update({ id: session.id }, { lastUsedAt: new Date() });
|
|
113
|
+
return this.issueTokens(user, session, settings);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Checks an access token's signature, issuer, audience and expiry.
|
|
117
|
+
* This does not check whether the session was ended since; see `isSessionStillAllowed`.
|
|
118
|
+
*
|
|
119
|
+
* @param accessToken - The token from the Authorization header.
|
|
120
|
+
* @returns The token's claims (user id, session id, roles...).
|
|
121
|
+
* @throws AuthError INVALID_TOKEN when any check fails.
|
|
122
|
+
*/
|
|
123
|
+
async verifyAccessToken(accessToken) {
|
|
124
|
+
const { publicKeysById } = await this.signingKeys.getSigningKeys();
|
|
125
|
+
const claims = (0, jwt_1.verifyJwt)(accessToken, (keyId) => publicKeysById.get(keyId), {
|
|
126
|
+
allowedAlgorithm: constants_1.SIGNING_ALGORITHM,
|
|
127
|
+
expectedIssuers: [this.issuer],
|
|
128
|
+
expectedAudiences: [this.issuer],
|
|
129
|
+
expectedTokenType: constants_1.ACCESS_TOKEN_JWT_TYPE,
|
|
130
|
+
});
|
|
131
|
+
if (!claims || typeof claims.sub !== 'string' || typeof claims.sid !== 'string')
|
|
132
|
+
throw new auth_error_1.AuthError(constants_1.AUTH_ERRORS.invalidAccessToken);
|
|
133
|
+
return claims;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Checks that the session has not been ended and its user is ACTIVE.
|
|
137
|
+
* Answers are cached for a few seconds, so signing out or suspending takes effect almost at once
|
|
138
|
+
* without a database query on every request.
|
|
139
|
+
*
|
|
140
|
+
* @param sessionId - The "sid" claim from the access token.
|
|
141
|
+
* @param userId - The "sub" claim from the access token.
|
|
142
|
+
* @returns True when requests from this session should still be accepted.
|
|
143
|
+
*/
|
|
144
|
+
async isSessionStillAllowed(sessionId, userId) {
|
|
145
|
+
const cached = this.sessionCheckCache.get(sessionId);
|
|
146
|
+
if (cached && Date.now() - cached.checkedAt < constants_1.SESSION_CHECK_CACHE_SECONDS * constants_1.SECOND_IN_MILLISECONDS)
|
|
147
|
+
return cached.isAllowed;
|
|
148
|
+
const matchingRows = await this.database
|
|
149
|
+
.getRepository(entities_1.SessionEntity)
|
|
150
|
+
.createQueryBuilder('session')
|
|
151
|
+
.innerJoin(entities_1.UserEntity, 'user', 'user.id = session.user_id')
|
|
152
|
+
.where('session.id = :sessionId AND session.user_id = :userId', { sessionId, userId })
|
|
153
|
+
.andWhere('session.revoked_at IS NULL AND session.expires_at > now()')
|
|
154
|
+
.andWhere('user.status = :activeStatus', { activeStatus: constants_1.ACCOUNT_STATUS.active })
|
|
155
|
+
.getCount();
|
|
156
|
+
const isAllowed = matchingRows === 1;
|
|
157
|
+
this.sessionCheckCache.set(sessionId, { isAllowed, checkedAt: Date.now() });
|
|
158
|
+
if (this.sessionCheckCache.size > constants_1.SESSION_CHECK_CACHE_MAX_ENTRIES)
|
|
159
|
+
this.sessionCheckCache.clear();
|
|
160
|
+
return isAllowed;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Ends one session.
|
|
164
|
+
*
|
|
165
|
+
* @param sessionId - The session to end.
|
|
166
|
+
* @param reason - Why it ended (stored, and shown in the audit log).
|
|
167
|
+
* @param userId - When given, the session is only ended if it belongs to this user.
|
|
168
|
+
* @returns False if nothing was ended (unknown, already ended, or someone else's session).
|
|
169
|
+
*/
|
|
170
|
+
async revokeSession(sessionId, reason, userId) {
|
|
171
|
+
const result = await this.database
|
|
172
|
+
.getRepository(entities_1.SessionEntity)
|
|
173
|
+
.update({ id: sessionId, revokedAt: (0, typeorm_1.IsNull)(), ...(userId ? { userId } : {}) }, { revokedAt: new Date(), revokedReason: reason });
|
|
174
|
+
this.sessionCheckCache.delete(sessionId);
|
|
175
|
+
const wasRevoked = (result.affected ?? 0) > 0;
|
|
176
|
+
if (wasRevoked) {
|
|
177
|
+
await this.events.record({ name: constants_1.AUTH_EVENTS.sessionRevoked, userId: userId ?? null, details: { sessionId, reason } });
|
|
178
|
+
}
|
|
179
|
+
return wasRevoked;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Ends every session of a user, e.g. after a password change.
|
|
183
|
+
*
|
|
184
|
+
* @param userId - The user to sign out.
|
|
185
|
+
* @param reason - Why the sessions ended.
|
|
186
|
+
* @param keepSessionId - When given, this session (the device making the request) stays signed in.
|
|
187
|
+
* @returns How many sessions were ended.
|
|
188
|
+
*/
|
|
189
|
+
async revokeAllSessions(userId, reason, keepSessionId) {
|
|
190
|
+
const result = await this.database
|
|
191
|
+
.getRepository(entities_1.SessionEntity)
|
|
192
|
+
.update({ userId, revokedAt: (0, typeorm_1.IsNull)(), ...(keepSessionId ? { id: (0, typeorm_1.Not)(keepSessionId) } : {}) }, { revokedAt: new Date(), revokedReason: reason });
|
|
193
|
+
this.sessionCheckCache.clear();
|
|
194
|
+
return result.affected ?? 0;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Lists the user's signed-in devices, most recently used first.
|
|
198
|
+
*
|
|
199
|
+
* @param userId - The user.
|
|
200
|
+
* @returns The sessions that have not ended or expired.
|
|
201
|
+
*/
|
|
202
|
+
listActiveSessions(userId) {
|
|
203
|
+
return this.database.getRepository(entities_1.SessionEntity).find({
|
|
204
|
+
where: { userId, revokedAt: (0, typeorm_1.IsNull)(), expiresAt: (0, typeorm_1.MoreThan)(new Date()) },
|
|
205
|
+
order: { lastUsedAt: constants_1.SORT_ORDER.newestFirst },
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Switches the organization a device is working in, and returns a fresh access token that carries it
|
|
210
|
+
* (in the "org_id" and "org_role" claims).
|
|
211
|
+
*
|
|
212
|
+
* @param sessionId - The device's session.
|
|
213
|
+
* @param organizationId - The organization to switch to, or null for none.
|
|
214
|
+
* @param settings - The current settings.
|
|
215
|
+
* @returns A new access token and its lifetime in seconds.
|
|
216
|
+
*/
|
|
217
|
+
async switchActiveOrganization(sessionId, organizationId, settings) {
|
|
218
|
+
const session = await this.database.getRepository(entities_1.SessionEntity).findOneOrFail({ where: { id: sessionId } });
|
|
219
|
+
session.activeOrganizationId = organizationId;
|
|
220
|
+
await this.database.getRepository(entities_1.SessionEntity).update({ id: sessionId }, { activeOrganizationId: organizationId });
|
|
221
|
+
const user = await this.database.getRepository(entities_1.UserEntity).findOneOrFail({ where: { id: session.userId } });
|
|
222
|
+
return this.createAccessToken(user, session, settings);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Creates a new access token and a new refresh token for a session.
|
|
226
|
+
*
|
|
227
|
+
* @param user - The session's user.
|
|
228
|
+
* @param session - The session the tokens belong to.
|
|
229
|
+
* @param settings - The current settings (token lifetimes).
|
|
230
|
+
* @returns The full token set to send to the client.
|
|
231
|
+
*/
|
|
232
|
+
async issueTokens(user, session, settings) {
|
|
233
|
+
const { accessToken, expiresIn } = await this.createAccessToken(user, session, settings);
|
|
234
|
+
const { plainToken: refreshToken, tokenHash } = (0, random_secrets_1.createRandomToken)(constants_1.TOKEN_PREFIX.refreshToken);
|
|
235
|
+
const refreshTokenLifetimeMs = settings.tokens.refreshTokenDays * constants_1.DAY_IN_SECONDS * constants_1.SECOND_IN_MILLISECONDS;
|
|
236
|
+
// A refresh token never outlives its session.
|
|
237
|
+
const refreshTokenExpiresAt = new Date(Math.min(Date.now() + refreshTokenLifetimeMs, session.expiresAt.getTime()));
|
|
238
|
+
await this.database.getRepository(entities_1.RefreshTokenEntity).insert({ sessionId: session.id, tokenHash, expiresAt: refreshTokenExpiresAt });
|
|
239
|
+
return {
|
|
240
|
+
accessToken,
|
|
241
|
+
expiresIn,
|
|
242
|
+
refreshToken,
|
|
243
|
+
refreshTokenExpiresAt: refreshTokenExpiresAt.toISOString(),
|
|
244
|
+
sessionId: session.id,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Signs an access token with the user's roles, how they signed in, and the active organization.
|
|
249
|
+
*
|
|
250
|
+
* @param user - The session's user.
|
|
251
|
+
* @param session - The session the token belongs to.
|
|
252
|
+
* @param settings - The current settings (access token lifetime).
|
|
253
|
+
* @returns The signed token and its lifetime in seconds.
|
|
254
|
+
*/
|
|
255
|
+
async createAccessToken(user, session, settings) {
|
|
256
|
+
const { currentKey } = await this.signingKeys.getSigningKeys();
|
|
257
|
+
const issuedAt = (0, time_1.currentUnixTimeSeconds)();
|
|
258
|
+
const expiresIn = settings.tokens.accessTokenMinutes * constants_1.MINUTE_IN_SECONDS;
|
|
259
|
+
const organizationMembership = session.activeOrganizationId
|
|
260
|
+
? await this.database.getRepository(entities_1.OrganizationMemberEntity).findOne({
|
|
261
|
+
where: { organizationId: session.activeOrganizationId, userId: user.id },
|
|
262
|
+
})
|
|
263
|
+
: null;
|
|
264
|
+
const claims = {
|
|
265
|
+
iss: this.issuer,
|
|
266
|
+
aud: this.issuer,
|
|
267
|
+
sub: user.id,
|
|
268
|
+
sid: session.id,
|
|
269
|
+
roles: user.roles,
|
|
270
|
+
amr: session.usedTwoFactor ? [session.signInMethod, constants_1.TWO_FACTOR_AMR_VALUE] : [session.signInMethod],
|
|
271
|
+
...(organizationMembership ? { org_id: organizationMembership.organizationId, org_role: organizationMembership.role } : {}),
|
|
272
|
+
iat: issuedAt,
|
|
273
|
+
exp: issuedAt + expiresIn,
|
|
274
|
+
jti: (0, node_crypto_1.randomUUID)(),
|
|
275
|
+
};
|
|
276
|
+
return { accessToken: (0, jwt_1.signJwt)(claims, currentKey, constants_1.ACCESS_TOKEN_JWT_TYPE), expiresIn };
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* An already-used refresh token came back: it was copied. End the session; the real user simply
|
|
280
|
+
* signs in again. Does nothing if the token was never ours.
|
|
281
|
+
*
|
|
282
|
+
* @param tokenHash - The hash of the token that was sent.
|
|
283
|
+
* @param request - Who sent it (for the audit log).
|
|
284
|
+
*/
|
|
285
|
+
async handleRefreshTokenReuse(tokenHash, request) {
|
|
286
|
+
const reusedToken = await this.database.getRepository(entities_1.RefreshTokenEntity).findOne({ where: { tokenHash, usedAt: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) } });
|
|
287
|
+
if (!reusedToken)
|
|
288
|
+
return;
|
|
289
|
+
const session = await this.database.getRepository(entities_1.SessionEntity).findOne({ where: { id: reusedToken.sessionId } });
|
|
290
|
+
if (!session || !(await this.revokeSession(session.id, constants_1.SESSION_END_REASON.refreshTokenReused)))
|
|
291
|
+
return;
|
|
292
|
+
this.logger.warn(`A used refresh token was presented again; session ${session.id} has been ended`);
|
|
293
|
+
await this.events.record({
|
|
294
|
+
name: constants_1.AUTH_EVENTS.refreshTokenReused,
|
|
295
|
+
userId: session.userId,
|
|
296
|
+
request,
|
|
297
|
+
details: { sessionId: session.id },
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
exports.SessionService = SessionService;
|
|
302
|
+
exports.SessionService = SessionService = __decorate([
|
|
303
|
+
(0, common_1.Injectable)(),
|
|
304
|
+
__param(0, (0, common_1.Inject)(constants_1.AUTH_OPTIONS_TOKEN)),
|
|
305
|
+
__metadata("design:paramtypes", [Object, signing_keys_service_1.SigningKeysService,
|
|
306
|
+
auth_events_service_1.AuthEventsService])
|
|
307
|
+
], SessionService);
|
|
308
|
+
//# sourceMappingURL=session.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.service.js","sourceRoot":"","sources":["../../../src/features/sessions/session.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { OrganizationRole } from '../../constants.js';
|
|
2
|
+
/** How a user proved who they are (see SIGN_IN_METHOD in constants.ts). */
|
|
3
|
+
export type { SignInMethod } from '../../constants.js';
|
|
4
|
+
/** What the app gets after signing in or refreshing. */
|
|
5
|
+
export interface TokenSet {
|
|
6
|
+
accessToken: string;
|
|
7
|
+
/** Seconds until the access token expires. */
|
|
8
|
+
expiresIn: number;
|
|
9
|
+
refreshToken: string;
|
|
10
|
+
refreshTokenExpiresAt: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
}
|
|
13
|
+
/** What is inside an access token. Read it in your routes with @CurrentUser(). */
|
|
14
|
+
export interface AccessTokenClaims {
|
|
15
|
+
/** Issuer: your API's URL. */
|
|
16
|
+
iss: string;
|
|
17
|
+
/** Audience: also your API's URL. */
|
|
18
|
+
aud: string;
|
|
19
|
+
/** The user's id. */
|
|
20
|
+
sub: string;
|
|
21
|
+
/** The session (device) id. */
|
|
22
|
+
sid: string;
|
|
23
|
+
/** App-wide roles, e.g. ["user"]. */
|
|
24
|
+
roles: string[];
|
|
25
|
+
/** How the user signed in, e.g. ["password", "two_factor"]. */
|
|
26
|
+
amr: string[];
|
|
27
|
+
/** Organization the user is working in on this device, if any. */
|
|
28
|
+
org_id?: string;
|
|
29
|
+
org_role?: OrganizationRole;
|
|
30
|
+
iat: number;
|
|
31
|
+
exp: number;
|
|
32
|
+
/** Unique token id. */
|
|
33
|
+
jti: string;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.types.js","sourceRoot":"","sources":["../../../src/features/sessions/session.types.ts"],"names":[],"mappings":""}
|