najm-auth 4.0.0 → 4.0.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/README.md CHANGED
@@ -1119,15 +1119,22 @@ errors cannot change the authentication result.
1119
1119
  ### Password Reset Tokens
1120
1120
 
1121
1121
  Reset and invite links are signed JWTs whose `jti` is stored in the configured
1122
- cache with the same expiry. `verifyResetToken()` atomically compares and
1123
- deletes that value, so exactly one concurrent caller can consume a link and a
1124
- stale link cannot delete the value for a newer one.
1122
+ cache with the same expiry. `consumeSetPasswordToken()` atomically compares and
1123
+ deletes that value while preserving whether the token was a reset or invite;
1124
+ the backward-compatible `verifyResetToken()` returns only the user id. Exactly
1125
+ one concurrent caller can consume a link, and a stale link cannot delete the
1126
+ value for a newer one.
1125
1127
 
1126
1128
  `AuthService.resetPassword()` validates the replacement password before
1127
1129
  consumption. Once consumed, a token stays consumed even if the later user
1128
1130
  mutation fails; restoring it would make the link replayable, so the user must
1129
1131
  request a new one.
1130
1132
 
1133
+ Accepting an account invitation also marks the destination email verified and
1134
+ activates the account when its status is `pending`. An ordinary password reset
1135
+ changes neither verification nor lifecycle status, and an explicitly inactive
1136
+ invited account remains inactive.
1137
+
1131
1138
  The built-in memory and Redis drivers implement the required atomic primitive.
1132
1139
  A custom cache driver may omit `compareAndDelete()` for compatibility with
1133
1140
  unrelated cache usage, but reset and invite consumption then fails closed. Do
package/dist/index.d.ts CHANGED
@@ -1233,6 +1233,11 @@ declare class CredentialSetupRequirementRepository {
1233
1233
  complete(userId: string, purpose: string): Promise<CredentialSetupRequirementRow | undefined>;
1234
1234
  }
1235
1235
 
1236
+ type SetPasswordTokenType = 'reset' | 'invite';
1237
+ interface ConsumedSetPasswordToken {
1238
+ userId: string;
1239
+ type: SetPasswordTokenType;
1240
+ }
1236
1241
  declare class TokenService {
1237
1242
  private tokenRepository;
1238
1243
  private cookieManager;
@@ -1480,6 +1485,12 @@ declare class TokenService {
1480
1485
  * request that then failed validation would cost the user their link for
1481
1486
  * nothing.
1482
1487
  */
1488
+ consumeSetPasswordToken(token: string): Promise<ConsumedSetPasswordToken>;
1489
+ /**
1490
+ * Backward-compatible user-id-only reset/invite token consumption.
1491
+ * Prefer `consumeSetPasswordToken()` when the caller must distinguish an
1492
+ * account invitation from an ordinary password reset.
1493
+ */
1483
1494
  verifyResetToken(token: string): Promise<string>;
1484
1495
  private getUserSessionVersion;
1485
1496
  }
@@ -3037,4 +3048,4 @@ declare const authSeed: (config: AuthSeedConfig) => Record<string, SeedEntry>;
3037
3048
  */
3038
3049
  declare function seedAuthData(config: SeedAuthDataConfig): Promise<SeedAuthDataResult>;
3039
3050
 
3040
- export { AUTH_CONFIG, AUTH_CORE_MODULE, en as AUTH_EN, AUTH_LOCALES, AUTH_LOGIN_RATE_LIMIT_ENV, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthLoginRateLimitConfig, type AuthPluginConfig, AuthQueries, type AuthRateLimitEnvironment, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, AuthSessionService, type AuthUser, CREDENTIAL_SETUP_CODES, CREDENTIAL_SETUP_MODULE, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type CredentialSetupChangeDto, type CredentialSetupCode, type CredentialSetupConfig, CredentialSetupController, type CredentialSetupOptions, type CredentialSetupPasswordOptions, type CredentialSetupPending, CredentialSetupRepository, CredentialSetupRequirementRepository, type CredentialSetupRequirementRow, CredentialSetupRequirementService, CredentialSetupService, type CredentialSetupSessionInfo, type CredentialSetupStarted, DEFAULT_AUTH_LOGIN_RATE_LIMIT, DEFAULT_CREDENTIAL_SETUP_COOKIE_NAME, DEFAULT_CREDENTIAL_SETUP_TTL_MS, type DefineRolesOptions, type EmailParam, EncryptionService, type GitHubOAuthConfig, type GoogleOAuthConfig, IdentityConfig, type IdentityResolver, type InviteUserDto, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, type LoginResult, NewPermission, NewRoleEntity, NewUser, type OAuthConfig, type OAuthProvider, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, PASSWORD_SETUP_PURPOSE, PUBLIC_REGISTRATION_MODULE, PasswordSetupService, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, type ProvisionUserInput, type ProvisionUserWithPasswordInput, type ProvisionUserWithSetupInput, ROLES, ROLE_GROUPS, type RefreshTokenDto, type RegisterDto, RegistrationController, type ResetPasswordDto, type ResolvedCredentialSetupConfig, ResolvedIdentityConfig, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type RunAsUser, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, type SessionCookieData, SessionInvalidationService, TOKEN_STATUS, TOKEN_TYPE, TemporaryCredentialInput, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, type UserListQuery, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authEmailRateLimitKey, authIdentityRateLimitKey, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createIdentityResolver, createPermissionDto, createRoleDto, createTokenDto, createUserDto, credentialSetupChangeDto, credentialSetupError, defaultCredentialSetupPasswordSchema, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, inviteUserDto, isAdmin, isAdministrator, isAuth, isEmailIdentifier, isEmpty, isFile, isPath, join, languageParam, loginDto, normalizeAuthIdentifier, normalizeSetupPurpose, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, registerDto, resetPasswordDto, resolveAuthLoginRateLimitConfig, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, userListQuery, verifyTokenDto, where };
3051
+ export { AUTH_CONFIG, AUTH_CORE_MODULE, en as AUTH_EN, AUTH_LOCALES, AUTH_LOGIN_RATE_LIMIT_ENV, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthLoginRateLimitConfig, type AuthPluginConfig, AuthQueries, type AuthRateLimitEnvironment, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, AuthSessionService, type AuthUser, CREDENTIAL_SETUP_CODES, CREDENTIAL_SETUP_MODULE, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, type ConsumedSetPasswordToken, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type CredentialSetupChangeDto, type CredentialSetupCode, type CredentialSetupConfig, CredentialSetupController, type CredentialSetupOptions, type CredentialSetupPasswordOptions, type CredentialSetupPending, CredentialSetupRepository, CredentialSetupRequirementRepository, type CredentialSetupRequirementRow, CredentialSetupRequirementService, CredentialSetupService, type CredentialSetupSessionInfo, type CredentialSetupStarted, DEFAULT_AUTH_LOGIN_RATE_LIMIT, DEFAULT_CREDENTIAL_SETUP_COOKIE_NAME, DEFAULT_CREDENTIAL_SETUP_TTL_MS, type DefineRolesOptions, type EmailParam, EncryptionService, type GitHubOAuthConfig, type GoogleOAuthConfig, IdentityConfig, type IdentityResolver, type InviteUserDto, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, type LoginResult, NewPermission, NewRoleEntity, NewUser, type OAuthConfig, type OAuthProvider, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, PASSWORD_SETUP_PURPOSE, PUBLIC_REGISTRATION_MODULE, PasswordSetupService, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, type ProvisionUserInput, type ProvisionUserWithPasswordInput, type ProvisionUserWithSetupInput, ROLES, ROLE_GROUPS, type RefreshTokenDto, type RegisterDto, RegistrationController, type ResetPasswordDto, type ResolvedCredentialSetupConfig, ResolvedIdentityConfig, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type RunAsUser, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, type SessionCookieData, SessionInvalidationService, type SetPasswordTokenType, TOKEN_STATUS, TOKEN_TYPE, TemporaryCredentialInput, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, type UserListQuery, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authEmailRateLimitKey, authIdentityRateLimitKey, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createIdentityResolver, createPermissionDto, createRoleDto, createTokenDto, createUserDto, credentialSetupChangeDto, credentialSetupError, defaultCredentialSetupPasswordSchema, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, inviteUserDto, isAdmin, isAdministrator, isAuth, isEmailIdentifier, isEmpty, isFile, isPath, join, languageParam, loginDto, normalizeAuthIdentifier, normalizeSetupPurpose, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, registerDto, resetPasswordDto, resolveAuthLoginRateLimitConfig, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, userListQuery, verifyTokenDto, where };
package/dist/index.js CHANGED
@@ -2708,7 +2708,7 @@ var TokenService = class TokenService2 {
2708
2708
  * request that then failed validation would cost the user their link for
2709
2709
  * nothing.
2710
2710
  */
2711
- async verifyResetToken(token) {
2711
+ async consumeSetPasswordToken(token) {
2712
2712
  let decoded;
2713
2713
  try {
2714
2714
  decoded = jwt.verify(token, this.config.jwt.refreshSecret);
@@ -2726,7 +2726,18 @@ var TokenService = class TokenService2 {
2726
2726
  if (!await consume.call(this.cache, key, decoded.jti)) {
2727
2727
  Err7(this.t("errors.invalidResetToken"));
2728
2728
  }
2729
- return decoded.userId;
2729
+ return {
2730
+ userId: decoded.userId,
2731
+ type: decoded.type
2732
+ };
2733
+ }
2734
+ /**
2735
+ * Backward-compatible user-id-only reset/invite token consumption.
2736
+ * Prefer `consumeSetPasswordToken()` when the caller must distinguish an
2737
+ * account invitation from an ordinary password reset.
2738
+ */
2739
+ async verifyResetToken(token) {
2740
+ return (await this.consumeSetPasswordToken(token)).userId;
2730
2741
  }
2731
2742
  async getUserSessionVersion(userId) {
2732
2743
  return this.invalidation.getSessionVersion(userId);
@@ -3818,10 +3829,18 @@ var AuthService = class AuthService2 {
3818
3829
  }
3819
3830
  async resetPassword(token, newPassword) {
3820
3831
  this.userValidator.validatePasswordStrength(newPassword);
3821
- const userId = await this.tokenService.verifyResetToken(token);
3822
- await this.userService.update(userId, { password: newPassword });
3823
- await this.tokenService.invalidateUserAccessTokens(userId);
3824
- await this.tokenService.revokeAllForUser(userId);
3832
+ const consumed = await this.tokenService.consumeSetPasswordToken(token);
3833
+ const user = await this.userService.getById(consumed.userId);
3834
+ const acceptsInvitation = consumed.type === "invite";
3835
+ await this.userService.update(consumed.userId, {
3836
+ password: newPassword,
3837
+ ...acceptsInvitation ? {
3838
+ emailVerified: true,
3839
+ ...user.status === "pending" ? { status: "active" } : {}
3840
+ } : {}
3841
+ });
3842
+ await this.tokenService.invalidateUserAccessTokens(consumed.userId);
3843
+ await this.tokenService.revokeAllForUser(consumed.userId);
3825
3844
  this.cookieManager.clearRefreshToken();
3826
3845
  this.cookieManager.clearSessionCookie();
3827
3846
  return { message: this.t("success.passwordReset") };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-auth",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "Authentication and authorization library for najm framework",
5
5
  "type": "module",
6
6
  "files": [