@aranzatech/aranza-auth 0.2.1 → 0.2.3

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/dist/index.cjs CHANGED
@@ -1,13 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ var swagger = require('@nestjs/swagger');
4
+ var classValidator = require('class-validator');
3
5
  var common = require('@nestjs/common');
4
- var core = require('@nestjs/core');
5
6
  var jwt = require('@nestjs/jwt');
6
7
  var passport = require('@nestjs/passport');
7
- var bcrypt2 = require('bcryptjs');
8
+ var bcrypt = require('bcryptjs');
8
9
  var crypto = require('crypto');
9
10
  var passportJwt = require('passport-jwt');
10
- var classValidator = require('class-validator');
11
+ var core = require('@nestjs/core');
11
12
 
12
13
  function _interopNamespace(e) {
13
14
  if (e && e.__esModule) return e;
@@ -27,7 +28,7 @@ function _interopNamespace(e) {
27
28
  return Object.freeze(n);
28
29
  }
29
30
 
30
- var bcrypt2__namespace = /*#__PURE__*/_interopNamespace(bcrypt2);
31
+ var bcrypt__namespace = /*#__PURE__*/_interopNamespace(bcrypt);
31
32
 
32
33
  var __defProp = Object.defineProperty;
33
34
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -51,18 +52,258 @@ var AUTH_RATE_LIMIT_PRESETS = {
51
52
  passwordReset: { name: "auth-password-reset", ttl: 6e4, limit: 3 }
52
53
  };
53
54
 
55
+ // src/constants/rate-limit.routes.ts
56
+ var AUTH_RATE_LIMIT_ROUTES = {
57
+ login: AUTH_RATE_LIMIT_PRESETS.credentials,
58
+ register: AUTH_RATE_LIMIT_PRESETS.credentials,
59
+ refresh: AUTH_RATE_LIMIT_PRESETS.credentials,
60
+ "forgot-password": AUTH_RATE_LIMIT_PRESETS.passwordReset,
61
+ "reset-password": AUTH_RATE_LIMIT_PRESETS.passwordReset,
62
+ "resend-verification": AUTH_RATE_LIMIT_PRESETS.passwordReset,
63
+ default: AUTH_RATE_LIMIT_PRESETS.default
64
+ };
65
+
54
66
  // src/constants/auth-errors.ts
55
67
  var AuthErrorCode = {
56
- INVALID_CREDENTIALS: "Invalid credentials",
57
- INVALID_REFRESH_TOKEN: "Invalid refresh token",
68
+ INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
69
+ INVALID_REFRESH_TOKEN: "INVALID_REFRESH_TOKEN",
58
70
  REFRESH_TOKEN_REUSE: "REFRESH_TOKEN_REUSE",
59
71
  ACCOUNT_DISABLED: "ACCOUNT_DISABLED",
72
+ ACCOUNT_NOT_FOUND: "ACCOUNT_NOT_FOUND",
60
73
  EMAIL_NOT_VERIFIED: "EMAIL_NOT_VERIFIED",
61
74
  TOKEN_INVALID_OR_EXPIRED: "TOKEN_INVALID_OR_EXPIRED",
62
75
  ACCOUNT_LOCKED: "ACCOUNT_LOCKED",
63
76
  INVALID_CURRENT_PASSWORD: "INVALID_CURRENT_PASSWORD",
64
- PASSWORD_UNCHANGED: "PASSWORD_UNCHANGED"
77
+ PASSWORD_UNCHANGED: "PASSWORD_UNCHANGED",
78
+ PASSWORD_CHANGED: "PASSWORD_CHANGED",
79
+ /** Missing or invalid Bearer token on a protected route. */
80
+ UNAUTHORIZED: "UNAUTHORIZED"
81
+ };
82
+ var AuthTokensDto = class {
83
+ };
84
+ __decorateClass([
85
+ swagger.ApiProperty({ type: String, example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." })
86
+ ], AuthTokensDto.prototype, "accessToken", 2);
87
+ __decorateClass([
88
+ swagger.ApiProperty({ type: String, example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." })
89
+ ], AuthTokensDto.prototype, "refreshToken", 2);
90
+ var ChangePasswordDto = class {
91
+ };
92
+ __decorateClass([
93
+ swagger.ApiProperty({ type: String, example: "CurrentPassword1", minLength: 1, maxLength: 128 }),
94
+ classValidator.IsString(),
95
+ classValidator.IsNotEmpty(),
96
+ classValidator.Length(1, 128)
97
+ ], ChangePasswordDto.prototype, "currentPassword", 2);
98
+ __decorateClass([
99
+ swagger.ApiProperty({ type: String, example: "NewPassword1", minLength: 8, maxLength: 128 }),
100
+ classValidator.IsString(),
101
+ classValidator.IsNotEmpty(),
102
+ classValidator.Length(8, 128)
103
+ ], ChangePasswordDto.prototype, "newPassword", 2);
104
+ var ForgotPasswordDto = class {
105
+ };
106
+ __decorateClass([
107
+ swagger.ApiProperty({ type: String, example: "user@example.com" }),
108
+ classValidator.IsEmail()
109
+ ], ForgotPasswordDto.prototype, "email", 2);
110
+ var LoginDto = class {
111
+ };
112
+ __decorateClass([
113
+ swagger.ApiPropertyOptional({ type: String, example: "user@example.com" }),
114
+ classValidator.IsOptional(),
115
+ classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
116
+ classValidator.IsEmail(),
117
+ classValidator.Length(3, 255)
118
+ ], LoginDto.prototype, "email", 2);
119
+ __decorateClass([
120
+ swagger.ApiPropertyOptional({ type: String, example: "johndoe" }),
121
+ classValidator.IsOptional(),
122
+ classValidator.IsString(),
123
+ classValidator.Length(3, 50)
124
+ ], LoginDto.prototype, "username", 2);
125
+ __decorateClass([
126
+ swagger.ApiProperty({ type: String, example: "Password1", minLength: 8, maxLength: 128 }),
127
+ classValidator.IsString(),
128
+ classValidator.IsNotEmpty(),
129
+ classValidator.Length(8, 128)
130
+ ], LoginDto.prototype, "password", 2);
131
+ var MeResponseDto = class {
132
+ };
133
+ __decorateClass([
134
+ swagger.ApiProperty({ type: String, example: "507f1f77bcf86cd799439011" })
135
+ ], MeResponseDto.prototype, "id", 2);
136
+ __decorateClass([
137
+ swagger.ApiPropertyOptional({ type: String, example: "user@example.com" })
138
+ ], MeResponseDto.prototype, "email", 2);
139
+ __decorateClass([
140
+ swagger.ApiPropertyOptional({ type: String, example: "johndoe" })
141
+ ], MeResponseDto.prototype, "username", 2);
142
+ __decorateClass([
143
+ swagger.ApiProperty({ type: Boolean, example: true })
144
+ ], MeResponseDto.prototype, "emailVerified", 2);
145
+ __decorateClass([
146
+ swagger.ApiProperty({ type: Boolean, example: false })
147
+ ], MeResponseDto.prototype, "disabled", 2);
148
+ __decorateClass([
149
+ swagger.ApiPropertyOptional({ type: String, format: "date-time" })
150
+ ], MeResponseDto.prototype, "lastLoginAt", 2);
151
+ __decorateClass([
152
+ swagger.ApiPropertyOptional({ type: String, format: "date-time" })
153
+ ], MeResponseDto.prototype, "passwordChangedAt", 2);
154
+ var RefreshTokenDto = class {
155
+ };
156
+ __decorateClass([
157
+ swagger.ApiProperty({ type: String, example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }),
158
+ classValidator.IsString(),
159
+ classValidator.IsNotEmpty()
160
+ ], RefreshTokenDto.prototype, "refreshToken", 2);
161
+ var RegisterAckDto = class {
162
+ };
163
+ __decorateClass([
164
+ swagger.ApiProperty({ type: Boolean, example: true, enum: [true] })
165
+ ], RegisterAckDto.prototype, "registered", 2);
166
+ var RegisterDto = class {
167
+ };
168
+ __decorateClass([
169
+ swagger.ApiPropertyOptional({ type: String, example: "user@example.com" }),
170
+ classValidator.IsOptional(),
171
+ classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
172
+ classValidator.IsEmail(),
173
+ classValidator.Length(3, 255)
174
+ ], RegisterDto.prototype, "email", 2);
175
+ __decorateClass([
176
+ swagger.ApiPropertyOptional({ type: String, example: "johndoe" }),
177
+ classValidator.IsOptional(),
178
+ classValidator.IsString(),
179
+ classValidator.Length(3, 50),
180
+ classValidator.Matches(/^[a-zA-Z0-9._-]+$/)
181
+ ], RegisterDto.prototype, "username", 2);
182
+ __decorateClass([
183
+ swagger.ApiProperty({ type: String, example: "Password1", minLength: 8, maxLength: 128 }),
184
+ classValidator.IsString(),
185
+ classValidator.IsNotEmpty(),
186
+ classValidator.Length(8, 128)
187
+ ], RegisterDto.prototype, "password", 2);
188
+ var ResendVerificationDto = class {
189
+ };
190
+ __decorateClass([
191
+ swagger.ApiProperty({ type: String, example: "user@example.com" }),
192
+ classValidator.IsEmail()
193
+ ], ResendVerificationDto.prototype, "email", 2);
194
+ var ResetPasswordDto = class {
195
+ };
196
+ __decorateClass([
197
+ swagger.ApiProperty({ type: String, example: "reset-token-from-email" }),
198
+ classValidator.IsString(),
199
+ classValidator.IsNotEmpty()
200
+ ], ResetPasswordDto.prototype, "token", 2);
201
+ __decorateClass([
202
+ swagger.ApiProperty({ type: String, example: "NewPassword1", minLength: 8, maxLength: 128 }),
203
+ classValidator.IsString(),
204
+ classValidator.IsNotEmpty(),
205
+ classValidator.Length(8, 128)
206
+ ], ResetPasswordDto.prototype, "newPassword", 2);
207
+ var VerifyEmailDto = class {
65
208
  };
209
+ __decorateClass([
210
+ swagger.ApiProperty({ type: String, example: "verification-token-from-email" }),
211
+ classValidator.IsString(),
212
+ classValidator.IsNotEmpty()
213
+ ], VerifyEmailDto.prototype, "token", 2);
214
+
215
+ // src/swagger/setup-swagger.util.ts
216
+ var AUTH_SWAGGER_MODELS = [
217
+ AuthTokensDto,
218
+ ChangePasswordDto,
219
+ ForgotPasswordDto,
220
+ LoginDto,
221
+ MeResponseDto,
222
+ RefreshTokenDto,
223
+ RegisterAckDto,
224
+ RegisterDto,
225
+ ResendVerificationDto,
226
+ ResetPasswordDto,
227
+ VerifyEmailDto
228
+ ];
229
+ function describeEnabledFeatures(features) {
230
+ const lines = [];
231
+ if (features.emailVerification === true) {
232
+ lines.push("- Email verification (`POST /auth/verify-email`, `POST /auth/resend-verification`)");
233
+ }
234
+ if (features.passwordReset === true) {
235
+ lines.push("- Password reset (`POST /auth/forgot-password`, `POST /auth/reset-password`)");
236
+ }
237
+ if (features.refreshTokenRotation === false) {
238
+ lines.push("- Refresh token rotation **disabled** (stateless refresh until JWT expiry)");
239
+ }
240
+ if (features.accountLockout === true) {
241
+ lines.push("- Account lockout after failed logins");
242
+ }
243
+ if (lines.length === 0) {
244
+ return "";
245
+ }
246
+ return `
247
+
248
+ ## Auth features enabled
249
+ ${lines.join("\n")}`;
250
+ }
251
+ function setupAuthSwagger(app, options = {}) {
252
+ const nestApp = app;
253
+ const baseDescription = options.description ?? "REST API with JWT authentication via @aranzatech/aranza-auth";
254
+ const config = new swagger.DocumentBuilder().setTitle(options.title ?? "API").setDescription(
255
+ `${baseDescription}${describeEnabledFeatures(options.features ?? {})}`
256
+ ).setVersion(options.version ?? "1.0").addBearerAuth(
257
+ {
258
+ type: "http",
259
+ scheme: "bearer",
260
+ bearerFormat: "JWT",
261
+ description: "Access token from POST /auth/login"
262
+ },
263
+ "access-token"
264
+ ).build();
265
+ const document = swagger.SwaggerModule.createDocument(nestApp, config, {
266
+ extraModels: [...AUTH_SWAGGER_MODELS]
267
+ });
268
+ if (options.exportPath != null) {
269
+ void import('fs/promises').then(
270
+ ({ writeFile }) => writeFile(options.exportPath, JSON.stringify(document, null, 2), "utf8")
271
+ );
272
+ }
273
+ swagger.SwaggerModule.setup(options.path ?? "api", nestApp, document);
274
+ }
275
+
276
+ // src/utils/refresh-token-cookie.util.ts
277
+ var DEFAULT_COOKIE_NAME = "refresh_token";
278
+ var DEFAULT_MAX_AGE_SECONDS = 7 * 24 * 60 * 60;
279
+ function resolveCookieOptions(options = {}) {
280
+ return {
281
+ name: options.name ?? DEFAULT_COOKIE_NAME,
282
+ path: options.path ?? "/auth/refresh",
283
+ secure: options.secure ?? true,
284
+ sameSite: options.sameSite ?? "strict",
285
+ maxAgeSeconds: options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS,
286
+ httpOnly: options.httpOnly ?? true
287
+ };
288
+ }
289
+ function formatCookieAttributes(options) {
290
+ const parts = [
291
+ `Path=${options.path}`,
292
+ `Max-Age=${options.maxAgeSeconds}`,
293
+ `SameSite=${options.sameSite}`
294
+ ];
295
+ if (options.secure) parts.push("Secure");
296
+ if (options.httpOnly) parts.push("HttpOnly");
297
+ return parts.join("; ");
298
+ }
299
+ function buildRefreshTokenCookie(refreshToken, options = {}) {
300
+ const resolved = resolveCookieOptions(options);
301
+ return `${resolved.name}=${encodeURIComponent(refreshToken)}; ${formatCookieAttributes(resolved)}`;
302
+ }
303
+ function buildClearRefreshTokenCookie(options = {}) {
304
+ const resolved = resolveCookieOptions(options);
305
+ return `${resolved.name}=; Path=${resolved.path}; Max-Age=0; HttpOnly`;
306
+ }
66
307
  var CurrentUser = common.createParamDecorator(
67
308
  (_data, ctx) => {
68
309
  const request = ctx.switchToHttp().getRequest();
@@ -71,8 +312,11 @@ var CurrentUser = common.createParamDecorator(
71
312
  );
72
313
  exports.JwtAuthGuard = class JwtAuthGuard extends passport.AuthGuard("jwt") {
73
314
  handleRequest(err, user, _info) {
74
- if (err != null || !user) {
75
- throw err ?? new common.UnauthorizedException();
315
+ if (err != null) {
316
+ throw err;
317
+ }
318
+ if (!user) {
319
+ throw new common.UnauthorizedException(AuthErrorCode.UNAUTHORIZED);
76
320
  }
77
321
  return user;
78
322
  }
@@ -91,7 +335,6 @@ var DUMMY_PASSWORD_HASH = "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZd
91
335
  exports.DefaultAuthHooks = class DefaultAuthHooks {
92
336
  async buildJwtPayload(account) {
93
337
  return {
94
- sub: account.id,
95
338
  ...account.email != null ? { email: account.email } : {},
96
339
  ...account.username != null ? { username: account.username } : {}
97
340
  };
@@ -158,49 +401,133 @@ function expiresAtFromTtlMs(ttlMs) {
158
401
  }
159
402
  var DEFAULT_EMAIL_VERIFICATION_TTL_MS = 24 * 60 * 60 * 1e3;
160
403
  var DEFAULT_PASSWORD_RESET_TTL_MS = 15 * 60 * 1e3;
404
+ var JWT_TOKEN_TYPE = {
405
+ ACCESS: "access",
406
+ REFRESH: "refresh"
407
+ };
408
+ function issuerAudienceClaims(options) {
409
+ return {
410
+ ...options.jwtIssuer != null ? { iss: options.jwtIssuer } : {},
411
+ ...options.jwtAudience != null ? { aud: options.jwtAudience } : {}
412
+ };
413
+ }
414
+ function buildAccessClaims(hookClaims, sub, pwdAt, options) {
415
+ return {
416
+ ...hookClaims,
417
+ sub,
418
+ typ: JWT_TOKEN_TYPE.ACCESS,
419
+ ...pwdAt != null ? { pwdAt } : {},
420
+ ...issuerAudienceClaims(options)
421
+ };
422
+ }
423
+ function buildRefreshClaims(sub, pwdAt, options) {
424
+ return {
425
+ sub,
426
+ typ: JWT_TOKEN_TYPE.REFRESH,
427
+ jti: crypto.randomUUID(),
428
+ ...pwdAt != null ? { pwdAt } : {},
429
+ ...issuerAudienceClaims(options)
430
+ };
431
+ }
432
+ function assertIssuerAudience(payload, options, errorCode) {
433
+ if (options.jwtIssuer != null && payload.iss != null && payload.iss !== options.jwtIssuer) {
434
+ throw new common.UnauthorizedException(errorCode);
435
+ }
436
+ if (options.jwtAudience != null && payload.aud != null && payload.aud !== options.jwtAudience) {
437
+ throw new common.UnauthorizedException(errorCode);
438
+ }
439
+ }
440
+ function assertAccessTokenClaims(payload, options) {
441
+ if (payload.typ != null && payload.typ !== JWT_TOKEN_TYPE.ACCESS) {
442
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_CREDENTIALS);
443
+ }
444
+ assertIssuerAudience(payload, options, AuthErrorCode.INVALID_CREDENTIALS);
445
+ }
446
+ function assertRefreshTokenClaims(payload, options) {
447
+ if (payload.typ !== JWT_TOKEN_TYPE.REFRESH) {
448
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
449
+ }
450
+ if (typeof payload.sub !== "string" || payload.sub.length === 0) {
451
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
452
+ }
453
+ assertIssuerAudience(payload, options, AuthErrorCode.INVALID_REFRESH_TOKEN);
454
+ return payload;
455
+ }
456
+ var HMAC_ALGORITHM = "sha256";
457
+ function hashRefreshTokenValue(refreshToken, secret) {
458
+ return crypto.createHmac(HMAC_ALGORITHM, secret).update(refreshToken).digest("hex");
459
+ }
460
+ function compareRefreshTokenValue(refreshToken, storedHash, secret) {
461
+ const computed = hashRefreshTokenValue(refreshToken, secret);
462
+ try {
463
+ const a = Buffer.from(computed, "hex");
464
+ const b = Buffer.from(storedHash, "hex");
465
+ if (a.length !== b.length) return false;
466
+ return crypto.timingSafeEqual(a, b);
467
+ } catch {
468
+ return false;
469
+ }
470
+ }
471
+
472
+ // src/services/token.service.ts
161
473
  var JWT_ALGORITHM = "HS256";
162
474
  exports.TokenService = class TokenService {
163
475
  constructor(jwtService, options) {
164
476
  this.jwtService = jwtService;
165
477
  this.options = options;
166
478
  }
167
- get bcryptRounds() {
168
- return this.options.bcryptRounds ?? 10;
479
+ signOptions(secret, expiresIn) {
480
+ return {
481
+ secret,
482
+ expiresIn,
483
+ algorithm: JWT_ALGORITHM,
484
+ ...this.options.jwtIssuer != null ? { issuer: this.options.jwtIssuer } : {},
485
+ ...this.options.jwtAudience != null ? { audience: this.options.jwtAudience } : {}
486
+ };
169
487
  }
170
- async signTokens(payload) {
488
+ async signTokens(accessClaims, refreshClaims) {
171
489
  const accessExpiresIn = this.options.expiresIn ?? "1h";
172
490
  const refreshExpiresIn = this.options.refreshExpiresIn ?? "7d";
173
491
  const [accessToken, refreshToken] = await Promise.all([
174
492
  this.jwtService.signAsync(
175
- payload,
176
- {
177
- secret: this.options.secret,
178
- expiresIn: accessExpiresIn,
179
- algorithm: JWT_ALGORITHM
180
- }
493
+ accessClaims,
494
+ this.signOptions(this.options.secret, accessExpiresIn)
181
495
  ),
182
496
  this.jwtService.signAsync(
183
- payload,
184
- {
185
- secret: this.options.refreshSecret,
186
- expiresIn: refreshExpiresIn,
187
- algorithm: JWT_ALGORITHM
188
- }
497
+ refreshClaims,
498
+ this.signOptions(this.options.refreshSecret, refreshExpiresIn)
189
499
  )
190
500
  ]);
191
501
  return { accessToken, refreshToken };
192
502
  }
193
503
  async verifyRefreshToken(refreshToken) {
194
- return this.jwtService.verifyAsync(refreshToken, {
195
- secret: this.options.refreshSecret,
196
- algorithms: [JWT_ALGORITHM]
197
- });
504
+ try {
505
+ const payload = await this.jwtService.verifyAsync(
506
+ refreshToken,
507
+ {
508
+ secret: this.options.refreshSecret,
509
+ algorithms: [JWT_ALGORITHM],
510
+ ...this.options.jwtIssuer != null ? { issuer: this.options.jwtIssuer } : {},
511
+ ...this.options.jwtAudience != null ? { audience: this.options.jwtAudience } : {}
512
+ }
513
+ );
514
+ return assertRefreshTokenClaims(payload, this.options);
515
+ } catch (error) {
516
+ if (error instanceof common.UnauthorizedException) {
517
+ throw error;
518
+ }
519
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
520
+ }
198
521
  }
199
522
  async hashRefreshToken(refreshToken) {
200
- return bcrypt2__namespace.hash(refreshToken, this.bcryptRounds);
523
+ return hashRefreshTokenValue(refreshToken, this.options.refreshSecret);
201
524
  }
202
- async compareRefreshToken(refreshToken, hash3) {
203
- return bcrypt2__namespace.compare(refreshToken, hash3);
525
+ async compareRefreshToken(refreshToken, hash2) {
526
+ return compareRefreshTokenValue(
527
+ refreshToken,
528
+ hash2,
529
+ this.options.refreshSecret
530
+ );
204
531
  }
205
532
  };
206
533
  exports.TokenService = __decorateClass([
@@ -208,6 +535,32 @@ exports.TokenService = __decorateClass([
208
535
  __decorateParam(0, common.Inject(jwt.JwtService)),
209
536
  __decorateParam(1, common.Inject(AUTH_MODULE_OPTIONS))
210
537
  ], exports.TokenService);
538
+ function passwordChangedAtMs(account) {
539
+ return account.passwordChangedAt?.getTime();
540
+ }
541
+ function buildPwdAtClaim(account) {
542
+ return passwordChangedAtMs(account);
543
+ }
544
+ function isAccountLocked(account, lockoutEnabled) {
545
+ if (!lockoutEnabled) return false;
546
+ const lockedUntil = "lockedUntil" in account ? account.lockedUntil : void 0;
547
+ if (lockedUntil == null) return false;
548
+ return lockedUntil > /* @__PURE__ */ new Date();
549
+ }
550
+ function assertAccountNotLocked(account, options) {
551
+ if (!isAccountLocked(account, options.features?.accountLockout === true)) {
552
+ return;
553
+ }
554
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_LOCKED);
555
+ }
556
+ function assertPasswordNotStale(payload, account) {
557
+ const changedAt = passwordChangedAtMs(account);
558
+ if (changedAt == null) return;
559
+ const tokenPwdAt = typeof payload.pwdAt === "number" ? payload.pwdAt : void 0;
560
+ if (tokenPwdAt == null || tokenPwdAt < changedAt) {
561
+ throw new common.UnauthorizedException(AuthErrorCode.PASSWORD_CHANGED);
562
+ }
563
+ }
211
564
 
212
565
  // src/services/auth.service.ts
213
566
  exports.AuthService = class AuthService {
@@ -256,7 +609,7 @@ exports.AuthService = class AuthService {
256
609
  resolveRegisterIdentifier(input, this.identifierField);
257
610
  this.assertRegisterEmailWhenVerificationEnabled(input);
258
611
  this.assertPasswordPolicy(dto.password);
259
- const passwordHash = await bcrypt2__namespace.hash(dto.password, this.bcryptRounds);
612
+ const passwordHash = await bcrypt__namespace.hash(dto.password, this.bcryptRounds);
260
613
  try {
261
614
  const account = await this.authRepository.create({
262
615
  ...input,
@@ -280,11 +633,8 @@ exports.AuthService = class AuthService {
280
633
  const account = await this.authRepository.findByIdentifierWithSecrets(
281
634
  identifier
282
635
  );
283
- if (account != null) {
284
- this.assertAccountNotLocked(account);
285
- }
286
636
  const passwordHash = account?.passwordHash ?? DUMMY_PASSWORD_HASH;
287
- const passwordMatches = await bcrypt2__namespace.compare(dto.password, passwordHash);
637
+ const passwordMatches = await bcrypt__namespace.compare(dto.password, passwordHash);
288
638
  if (account?.passwordHash == null || !passwordMatches) {
289
639
  if (account != null && this.accountLockoutEnabled) {
290
640
  await this.authRepository.recordLoginFailure(
@@ -294,6 +644,7 @@ exports.AuthService = class AuthService {
294
644
  }
295
645
  throw new common.UnauthorizedException(AuthErrorCode.INVALID_CREDENTIALS);
296
646
  }
647
+ assertAccountNotLocked(account, this.options);
297
648
  this.assertAccountActive(account);
298
649
  await this.authRepository.recordLoginSuccess(account.id);
299
650
  return this.issueTokens(account);
@@ -302,14 +653,25 @@ exports.AuthService = class AuthService {
302
653
  let payload;
303
654
  try {
304
655
  payload = await this.tokenService.verifyRefreshToken(refreshToken);
305
- } catch {
656
+ } catch (error) {
657
+ if (error instanceof common.UnauthorizedException) {
658
+ throw error;
659
+ }
306
660
  throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
307
661
  }
308
662
  const account = await this.authRepository.findByIdWithSecrets(payload.sub);
309
663
  if (account == null) {
310
664
  throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
311
665
  }
666
+ assertPasswordNotStale(
667
+ {
668
+ sub: payload.sub,
669
+ ...payload.pwdAt != null ? { pwdAt: payload.pwdAt } : {}
670
+ },
671
+ account
672
+ );
312
673
  this.assertAccountActive(account);
674
+ assertAccountNotLocked(account, this.options);
313
675
  if (this.rotateRefreshToken) {
314
676
  if (account.refreshTokenHash == null) {
315
677
  throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
@@ -322,6 +684,9 @@ exports.AuthService = class AuthService {
322
684
  await this.authRepository.updateRefreshTokenHash(account.id, null);
323
685
  throw new common.UnauthorizedException(AuthErrorCode.REFRESH_TOKEN_REUSE);
324
686
  }
687
+ return this.issueTokens(account, {
688
+ expectedRefreshHash: account.refreshTokenHash
689
+ });
325
690
  }
326
691
  return this.issueTokens(account);
327
692
  }
@@ -332,7 +697,7 @@ exports.AuthService = class AuthService {
332
697
  async me(authId) {
333
698
  const account = await this.authRepository.findById(authId);
334
699
  if (account == null) {
335
- throw new common.UnauthorizedException("Account not found");
700
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_NOT_FOUND);
336
701
  }
337
702
  if (this.hooks.enrichMe != null) {
338
703
  return this.hooks.enrichMe(account);
@@ -373,18 +738,37 @@ exports.AuthService = class AuthService {
373
738
  throw new common.BadRequestException(AuthErrorCode.TOKEN_INVALID_OR_EXPIRED);
374
739
  }
375
740
  this.assertPasswordPolicy(newPassword);
376
- const passwordHash = await bcrypt2__namespace.hash(newPassword, this.bcryptRounds);
741
+ const samePassword = await bcrypt__namespace.compare(
742
+ newPassword,
743
+ account.passwordHash
744
+ );
745
+ if (samePassword) {
746
+ throw new common.BadRequestException(AuthErrorCode.PASSWORD_UNCHANGED);
747
+ }
748
+ const passwordHash = await bcrypt__namespace.hash(newPassword, this.bcryptRounds);
377
749
  await this.authRepository.updatePasswordHash(account.id, passwordHash);
378
750
  await this.authRepository.clearResetToken(account.id);
379
751
  await this.authRepository.updateRefreshTokenHash(account.id, null);
380
752
  return { reset: true };
381
753
  }
754
+ async resendVerification(email) {
755
+ this.assertEmailVerificationEnabled();
756
+ this.assertEmailHookWhenVerificationEnabled();
757
+ const normalizedEmail = normalizeIdentifier(email);
758
+ const account = await this.authRepository.findUnverifiedByEmail(
759
+ normalizedEmail
760
+ );
761
+ if (account != null && !account.disabled) {
762
+ await this.sendVerificationEmail(account);
763
+ }
764
+ return { sent: true };
765
+ }
382
766
  async changePassword(authId, currentPassword, newPassword) {
383
767
  const account = await this.authRepository.findByIdWithSecrets(authId);
384
768
  if (account?.passwordHash == null) {
385
769
  throw new common.UnauthorizedException(AuthErrorCode.INVALID_CURRENT_PASSWORD);
386
770
  }
387
- const currentMatches = await bcrypt2__namespace.compare(
771
+ const currentMatches = await bcrypt__namespace.compare(
388
772
  currentPassword,
389
773
  account.passwordHash
390
774
  );
@@ -395,19 +779,11 @@ exports.AuthService = class AuthService {
395
779
  throw new common.BadRequestException(AuthErrorCode.PASSWORD_UNCHANGED);
396
780
  }
397
781
  this.assertPasswordPolicy(newPassword);
398
- const passwordHash = await bcrypt2__namespace.hash(newPassword, this.bcryptRounds);
782
+ const passwordHash = await bcrypt__namespace.hash(newPassword, this.bcryptRounds);
399
783
  await this.authRepository.updatePasswordHash(account.id, passwordHash);
400
784
  await this.authRepository.updateRefreshTokenHash(account.id, null);
401
785
  return { changed: true };
402
786
  }
403
- assertAccountNotLocked(account) {
404
- if (!this.accountLockoutEnabled || account.lockedUntil == null) {
405
- return;
406
- }
407
- if (account.lockedUntil > /* @__PURE__ */ new Date()) {
408
- throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_LOCKED);
409
- }
410
- }
411
787
  assertAccountActive(account) {
412
788
  if (account.disabled) {
413
789
  throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_DISABLED);
@@ -421,20 +797,33 @@ exports.AuthService = class AuthService {
421
797
  assertPasswordComplexity(password);
422
798
  }
423
799
  }
424
- async issueTokens(account) {
425
- const payload = await this.hooks.buildJwtPayload(account);
426
- const tokens = await this.tokenService.signTokens({
427
- ...payload,
428
- sub: account.id
429
- });
800
+ async issueTokens(account, rotation) {
801
+ const hookPayload = await this.hooks.buildJwtPayload(account);
802
+ const pwdAt = buildPwdAtClaim(account);
803
+ const tokens = await this.tokenService.signTokens(
804
+ buildAccessClaims(hookPayload, account.id, pwdAt, this.options),
805
+ buildRefreshClaims(account.id, pwdAt, this.options)
806
+ );
430
807
  if (this.rotateRefreshToken) {
431
808
  const refreshTokenHash = await this.tokenService.hashRefreshToken(
432
809
  tokens.refreshToken
433
810
  );
434
- await this.authRepository.updateRefreshTokenHash(
435
- account.id,
436
- refreshTokenHash
437
- );
811
+ if (rotation?.expectedRefreshHash != null) {
812
+ const swapped = await this.authRepository.rotateRefreshTokenHashIfMatch(
813
+ account.id,
814
+ rotation.expectedRefreshHash,
815
+ refreshTokenHash
816
+ );
817
+ if (!swapped) {
818
+ await this.authRepository.updateRefreshTokenHash(account.id, null);
819
+ throw new common.UnauthorizedException(AuthErrorCode.REFRESH_TOKEN_REUSE);
820
+ }
821
+ } else {
822
+ await this.authRepository.updateRefreshTokenHash(
823
+ account.id,
824
+ refreshTokenHash
825
+ );
826
+ }
438
827
  }
439
828
  await this.hooks.onAfterLogin?.(account);
440
829
  return tokens;
@@ -504,6 +893,21 @@ exports.AuthService = __decorateClass([
504
893
  __decorateParam(2, common.Inject(AUTH_HOOKS)),
505
894
  __decorateParam(3, common.Inject(exports.TokenService))
506
895
  ], exports.AuthService);
896
+ function ApiAuthUnauthorizedResponse(...codes) {
897
+ const messageEnum = codes.length > 0 ? codes : Object.values(AuthErrorCode);
898
+ return common.applyDecorators(
899
+ swagger.ApiUnauthorizedResponse({
900
+ description: "Unauthorized \u2014 `message` is an `AuthErrorCode` value",
901
+ schema: {
902
+ type: "object",
903
+ properties: {
904
+ statusCode: { type: "number", example: 401 },
905
+ message: { type: "string", enum: messageEnum }
906
+ }
907
+ }
908
+ })
909
+ );
910
+ }
507
911
 
508
912
  // src/controllers/auth.controller.ts
509
913
  var AuthController = class {
@@ -528,6 +932,9 @@ var AuthController = class {
528
932
  verifyEmail(dto) {
529
933
  return this.authService.verifyEmail(dto.token);
530
934
  }
935
+ resendVerification(dto) {
936
+ return this.authService.resendVerification(dto.email);
937
+ }
531
938
  forgotPassword(dto) {
532
939
  return this.authService.forgotPassword(dto.email);
533
940
  }
@@ -544,52 +951,118 @@ var AuthController = class {
544
951
  };
545
952
  __decorateClass([
546
953
  common.Post("register"),
954
+ swagger.ApiOperation({ summary: "Register a new account" }),
955
+ swagger.ApiResponse({ status: 201, type: RegisterAckDto }),
547
956
  __decorateParam(0, common.Body())
548
957
  ], AuthController.prototype, "register", 1);
549
958
  __decorateClass([
550
959
  common.Post("login"),
960
+ common.HttpCode(common.HttpStatus.OK),
961
+ swagger.ApiOperation({ summary: "Login and receive JWT tokens" }),
962
+ swagger.ApiResponse({ status: 200, type: AuthTokensDto }),
963
+ ApiAuthUnauthorizedResponse(
964
+ AuthErrorCode.INVALID_CREDENTIALS,
965
+ AuthErrorCode.ACCOUNT_LOCKED,
966
+ AuthErrorCode.EMAIL_NOT_VERIFIED,
967
+ AuthErrorCode.ACCOUNT_DISABLED
968
+ ),
551
969
  __decorateParam(0, common.Body())
552
970
  ], AuthController.prototype, "login", 1);
553
971
  __decorateClass([
554
972
  common.Post("refresh"),
555
973
  common.HttpCode(common.HttpStatus.OK),
974
+ swagger.ApiOperation({ summary: "Refresh access token using refresh token" }),
975
+ swagger.ApiResponse({ status: 200, type: AuthTokensDto }),
976
+ ApiAuthUnauthorizedResponse(
977
+ AuthErrorCode.INVALID_REFRESH_TOKEN,
978
+ AuthErrorCode.REFRESH_TOKEN_REUSE,
979
+ AuthErrorCode.PASSWORD_CHANGED,
980
+ AuthErrorCode.EMAIL_NOT_VERIFIED,
981
+ AuthErrorCode.ACCOUNT_LOCKED
982
+ ),
556
983
  __decorateParam(0, common.Body())
557
984
  ], AuthController.prototype, "refresh", 1);
558
985
  __decorateClass([
559
986
  common.Post("logout"),
560
987
  common.UseGuards(exports.JwtAuthGuard),
988
+ swagger.ApiBearerAuth("access-token"),
561
989
  common.HttpCode(common.HttpStatus.OK),
990
+ swagger.ApiOperation({ summary: "Logout and revoke refresh token" }),
991
+ swagger.ApiResponse({ status: 200, schema: { example: { loggedOut: true } } }),
992
+ ApiAuthUnauthorizedResponse(AuthErrorCode.UNAUTHORIZED),
562
993
  __decorateParam(0, CurrentUser())
563
994
  ], AuthController.prototype, "logout", 1);
564
995
  __decorateClass([
565
996
  common.Get("me"),
566
997
  common.UseGuards(exports.JwtAuthGuard),
998
+ swagger.ApiBearerAuth("access-token"),
999
+ swagger.ApiOperation({ summary: "Get current authenticated user profile" }),
1000
+ swagger.ApiResponse({ status: 200, type: MeResponseDto }),
1001
+ ApiAuthUnauthorizedResponse(
1002
+ AuthErrorCode.UNAUTHORIZED,
1003
+ AuthErrorCode.ACCOUNT_NOT_FOUND,
1004
+ AuthErrorCode.PASSWORD_CHANGED,
1005
+ AuthErrorCode.EMAIL_NOT_VERIFIED,
1006
+ AuthErrorCode.ACCOUNT_LOCKED
1007
+ ),
567
1008
  __decorateParam(0, CurrentUser())
568
1009
  ], AuthController.prototype, "me", 1);
569
1010
  __decorateClass([
570
1011
  common.Post("verify-email"),
571
1012
  common.HttpCode(common.HttpStatus.OK),
1013
+ swagger.ApiOperation({
1014
+ summary: "Verify email with token (requires emailVerification feature)"
1015
+ }),
1016
+ swagger.ApiResponse({ status: 200, schema: { example: { verified: true } } }),
1017
+ swagger.ApiResponse({ status: 404, description: "Feature disabled" }),
572
1018
  __decorateParam(0, common.Body())
573
1019
  ], AuthController.prototype, "verifyEmail", 1);
1020
+ __decorateClass([
1021
+ common.Post("resend-verification"),
1022
+ common.HttpCode(common.HttpStatus.OK),
1023
+ swagger.ApiOperation({
1024
+ summary: "Resend verification email (requires emailVerification feature)"
1025
+ }),
1026
+ swagger.ApiResponse({ status: 200, schema: { example: { sent: true } } }),
1027
+ swagger.ApiResponse({ status: 404, description: "Feature disabled" }),
1028
+ __decorateParam(0, common.Body())
1029
+ ], AuthController.prototype, "resendVerification", 1);
574
1030
  __decorateClass([
575
1031
  common.Post("forgot-password"),
576
1032
  common.HttpCode(common.HttpStatus.OK),
1033
+ swagger.ApiOperation({
1034
+ summary: "Request password reset email (requires passwordReset feature)"
1035
+ }),
1036
+ swagger.ApiResponse({ status: 200, schema: { example: { sent: true } } }),
1037
+ swagger.ApiResponse({ status: 404, description: "Feature disabled" }),
577
1038
  __decorateParam(0, common.Body())
578
1039
  ], AuthController.prototype, "forgotPassword", 1);
579
1040
  __decorateClass([
580
1041
  common.Post("reset-password"),
581
1042
  common.HttpCode(common.HttpStatus.OK),
1043
+ swagger.ApiOperation({
1044
+ summary: "Reset password with token (requires passwordReset feature)"
1045
+ }),
1046
+ swagger.ApiResponse({ status: 200, schema: { example: { reset: true } } }),
1047
+ swagger.ApiResponse({ status: 404, description: "Feature disabled" }),
582
1048
  __decorateParam(0, common.Body())
583
1049
  ], AuthController.prototype, "resetPassword", 1);
584
1050
  __decorateClass([
585
1051
  common.Post("change-password"),
586
1052
  common.UseGuards(exports.JwtAuthGuard),
1053
+ swagger.ApiBearerAuth("access-token"),
587
1054
  common.HttpCode(common.HttpStatus.OK),
1055
+ swagger.ApiOperation({ summary: "Change password for authenticated user" }),
1056
+ swagger.ApiResponse({ status: 200, schema: { example: { changed: true } } }),
1057
+ ApiAuthUnauthorizedResponse(
1058
+ AuthErrorCode.UNAUTHORIZED,
1059
+ AuthErrorCode.INVALID_CURRENT_PASSWORD
1060
+ ),
588
1061
  __decorateParam(0, CurrentUser()),
589
1062
  __decorateParam(1, common.Body())
590
1063
  ], AuthController.prototype, "changePassword", 1);
591
1064
  AuthController = __decorateClass([
592
- common.Controller("auth"),
1065
+ swagger.ApiTags("auth"),
593
1066
  __decorateParam(0, common.Inject(exports.AuthService))
594
1067
  ], AuthController);
595
1068
 
@@ -611,19 +1084,55 @@ var JwtStrategy = class extends passport.PassportStrategy(passportJwt.Strategy)
611
1084
  jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
612
1085
  ignoreExpiration: false,
613
1086
  secretOrKey: options.secret,
614
- algorithms: ["HS256"]
1087
+ algorithms: ["HS256"],
1088
+ ...options.jwtIssuer != null ? { issuer: options.jwtIssuer } : {},
1089
+ ...options.jwtAudience != null ? { audience: options.jwtAudience } : {}
615
1090
  });
616
1091
  this.options = options;
617
1092
  this.authRepository = authRepository;
1093
+ this.validationCache = /* @__PURE__ */ new Map();
618
1094
  }
619
- async validate(payload) {
620
- const account = await this.authRepository.findById(payload.sub);
621
- if (account == null || account.disabled) {
622
- throw new common.UnauthorizedException("Account not found or inactive");
1095
+ get cacheTtlMs() {
1096
+ return this.options.jwtValidationCacheTtlMs ?? 0;
1097
+ }
1098
+ getCachedAccount(sub) {
1099
+ const cached = this.validationCache.get(sub);
1100
+ if (cached == null || cached.expiresAt <= Date.now()) {
1101
+ if (cached != null) this.validationCache.delete(sub);
1102
+ return null;
1103
+ }
1104
+ return cached.account;
1105
+ }
1106
+ cacheAccount(sub, account) {
1107
+ if (this.cacheTtlMs <= 0) return;
1108
+ this.validationCache.set(sub, {
1109
+ account,
1110
+ expiresAt: Date.now() + this.cacheTtlMs
1111
+ });
1112
+ }
1113
+ assertAccountActive(account, payload) {
1114
+ if (account.disabled) {
1115
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_DISABLED);
623
1116
  }
1117
+ assertAccountNotLocked(account, this.options);
624
1118
  if (this.options.features?.emailVerification === true && !account.emailVerified) {
625
1119
  throw new common.UnauthorizedException(AuthErrorCode.EMAIL_NOT_VERIFIED);
626
1120
  }
1121
+ assertPasswordNotStale(payload, account);
1122
+ }
1123
+ async validate(payload) {
1124
+ assertAccessTokenClaims(payload, this.options);
1125
+ const cached = this.getCachedAccount(payload.sub);
1126
+ if (cached != null) {
1127
+ this.assertAccountActive(cached, payload);
1128
+ return payload;
1129
+ }
1130
+ const account = await this.authRepository.findById(payload.sub);
1131
+ if (account == null) {
1132
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_NOT_FOUND);
1133
+ }
1134
+ this.assertAccountActive(account, payload);
1135
+ this.cacheAccount(payload.sub, account);
627
1136
  return payload;
628
1137
  }
629
1138
  };
@@ -632,8 +1141,6 @@ JwtStrategy = __decorateClass([
632
1141
  __decorateParam(0, common.Inject(AUTH_MODULE_OPTIONS)),
633
1142
  __decorateParam(1, common.Inject(AUTH_REPOSITORY))
634
1143
  ], JwtStrategy);
635
-
636
- // src/utils/hooks-provider.util.ts
637
1144
  function createHooksProvider(options) {
638
1145
  if (options.hooksProvider != null) {
639
1146
  return options.hooksProvider;
@@ -641,7 +1148,8 @@ function createHooksProvider(options) {
641
1148
  const HooksClass = options.hooks ?? exports.DefaultAuthHooks;
642
1149
  return {
643
1150
  provide: AUTH_HOOKS,
644
- useClass: HooksClass
1151
+ inject: [core.ModuleRef],
1152
+ useFactory: (moduleRef) => moduleRef.create(HooksClass)
645
1153
  };
646
1154
  }
647
1155
 
@@ -681,6 +1189,17 @@ function validateAuthModuleOptions(options) {
681
1189
  "AuthModule: passwordResetTokenTtlMs must be at least 60000 (1 minute)"
682
1190
  );
683
1191
  }
1192
+ if (options.features?.refreshTokenRotation === false) {
1193
+ console.warn(
1194
+ "[aranza-auth] features.refreshTokenRotation is false \u2014 refresh tokens are stateless until JWT expiry; stolen tokens cannot be revoked server-side."
1195
+ );
1196
+ }
1197
+ const cacheTtl = options.jwtValidationCacheTtlMs ?? 0;
1198
+ if (cacheTtl < 0 || cacheTtl > 3e5) {
1199
+ throw new Error(
1200
+ "AuthModule: jwtValidationCacheTtlMs must be between 0 and 300000 (5 minutes)"
1201
+ );
1202
+ }
684
1203
  }
685
1204
 
686
1205
  // src/auth.module.ts
@@ -698,15 +1217,33 @@ function createCoreProviders(options) {
698
1217
  exports.JwtAuthGuard
699
1218
  ];
700
1219
  }
701
- function createAsyncHooksProvider(options) {
702
- if (options.hooksProvider != null) {
703
- return options.hooksProvider;
704
- }
705
- const HooksClass = options.hooks ?? exports.DefaultAuthHooks;
1220
+ function createAsyncProviders(options) {
1221
+ return [
1222
+ {
1223
+ provide: AUTH_MODULE_OPTIONS,
1224
+ inject: options.inject ?? [],
1225
+ useFactory: async (...args) => {
1226
+ const config = await options.useFactory(...args);
1227
+ validateAuthModuleOptions(config);
1228
+ return config;
1229
+ }
1230
+ },
1231
+ createHooksProvider(options),
1232
+ exports.AuthService,
1233
+ exports.TokenService,
1234
+ JwtStrategy,
1235
+ exports.JwtAuthGuard
1236
+ ];
1237
+ }
1238
+ function jwtModuleOptions(opts) {
706
1239
  return {
707
- provide: AUTH_HOOKS,
708
- inject: [core.ModuleRef],
709
- useFactory: (moduleRef) => moduleRef.create(HooksClass)
1240
+ secret: opts.secret,
1241
+ signOptions: {
1242
+ expiresIn: opts.expiresIn ?? "1h",
1243
+ algorithm: "HS256",
1244
+ ...opts.jwtIssuer != null ? { issuer: opts.jwtIssuer } : {},
1245
+ ...opts.jwtAudience != null ? { audience: opts.jwtAudience } : {}
1246
+ }
710
1247
  };
711
1248
  }
712
1249
  function createAuthImports() {
@@ -714,13 +1251,7 @@ function createAuthImports() {
714
1251
  passport.PassportModule.register({ defaultStrategy: "jwt" }),
715
1252
  jwt.JwtModule.registerAsync({
716
1253
  inject: [AUTH_MODULE_OPTIONS],
717
- useFactory: (opts) => ({
718
- secret: opts.secret,
719
- signOptions: {
720
- expiresIn: opts.expiresIn ?? "1h",
721
- algorithm: "HS256"
722
- }
723
- })
1254
+ useFactory: (opts) => jwtModuleOptions(opts)
724
1255
  })
725
1256
  ];
726
1257
  }
@@ -731,24 +1262,6 @@ function mergeImports(userImports) {
731
1262
  }
732
1263
  return merged;
733
1264
  }
734
- function createAsyncProviders(options) {
735
- return [
736
- {
737
- provide: AUTH_MODULE_OPTIONS,
738
- inject: options.inject ?? [],
739
- useFactory: async (...args) => {
740
- const config = await options.useFactory(...args);
741
- validateAuthModuleOptions(config);
742
- return config;
743
- }
744
- },
745
- createAsyncHooksProvider(options),
746
- exports.AuthService,
747
- exports.TokenService,
748
- JwtStrategy,
749
- exports.JwtAuthGuard
750
- ];
751
- }
752
1265
  exports.AuthModule = class AuthModule {
753
1266
  static forRoot(options) {
754
1267
  const routePrefix = options.routePrefix ?? "auth";
@@ -793,93 +1306,10 @@ exports.AuthModule = __decorateClass([
793
1306
  common.Module({})
794
1307
  ], exports.AuthModule);
795
1308
 
796
- // src/dto/auth-tokens.dto.ts
797
- var AuthTokensDto = class {
798
- };
799
- var ChangePasswordDto = class {
800
- };
801
- __decorateClass([
802
- classValidator.IsString(),
803
- classValidator.IsNotEmpty()
804
- ], ChangePasswordDto.prototype, "currentPassword", 2);
805
- __decorateClass([
806
- classValidator.IsString(),
807
- classValidator.IsNotEmpty(),
808
- classValidator.Length(8, 128)
809
- ], ChangePasswordDto.prototype, "newPassword", 2);
810
- var ForgotPasswordDto = class {
811
- };
812
- __decorateClass([
813
- classValidator.IsEmail()
814
- ], ForgotPasswordDto.prototype, "email", 2);
815
- var LoginDto = class {
816
- };
817
- __decorateClass([
818
- classValidator.IsOptional(),
819
- classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
820
- classValidator.IsEmail(),
821
- classValidator.Length(3, 255)
822
- ], LoginDto.prototype, "email", 2);
823
- __decorateClass([
824
- classValidator.IsOptional(),
825
- classValidator.IsString(),
826
- classValidator.Length(3, 50)
827
- ], LoginDto.prototype, "username", 2);
828
- __decorateClass([
829
- classValidator.IsString(),
830
- classValidator.IsNotEmpty(),
831
- classValidator.Length(8, 128)
832
- ], LoginDto.prototype, "password", 2);
833
- var RefreshTokenDto = class {
834
- };
835
- __decorateClass([
836
- classValidator.IsString(),
837
- classValidator.IsNotEmpty()
838
- ], RefreshTokenDto.prototype, "refreshToken", 2);
839
-
840
- // src/dto/register-ack.dto.ts
841
- var RegisterAckDto = class {
842
- };
843
- var RegisterDto = class {
844
- };
845
- __decorateClass([
846
- classValidator.IsOptional(),
847
- classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
848
- classValidator.IsEmail(),
849
- classValidator.Length(3, 255)
850
- ], RegisterDto.prototype, "email", 2);
851
- __decorateClass([
852
- classValidator.IsOptional(),
853
- classValidator.IsString(),
854
- classValidator.Length(3, 50),
855
- classValidator.Matches(/^[a-zA-Z0-9._-]+$/)
856
- ], RegisterDto.prototype, "username", 2);
857
- __decorateClass([
858
- classValidator.IsString(),
859
- classValidator.IsNotEmpty(),
860
- classValidator.Length(8, 128)
861
- ], RegisterDto.prototype, "password", 2);
862
- var ResetPasswordDto = class {
863
- };
864
- __decorateClass([
865
- classValidator.IsString(),
866
- classValidator.IsNotEmpty()
867
- ], ResetPasswordDto.prototype, "token", 2);
868
- __decorateClass([
869
- classValidator.IsString(),
870
- classValidator.IsNotEmpty(),
871
- classValidator.Length(8, 128)
872
- ], ResetPasswordDto.prototype, "newPassword", 2);
873
- var VerifyEmailDto = class {
874
- };
875
- __decorateClass([
876
- classValidator.IsString(),
877
- classValidator.IsNotEmpty()
878
- ], VerifyEmailDto.prototype, "token", 2);
879
-
880
1309
  exports.AUTH_HOOKS = AUTH_HOOKS;
881
1310
  exports.AUTH_MODULE_OPTIONS = AUTH_MODULE_OPTIONS;
882
1311
  exports.AUTH_RATE_LIMIT_PRESETS = AUTH_RATE_LIMIT_PRESETS;
1312
+ exports.AUTH_RATE_LIMIT_ROUTES = AUTH_RATE_LIMIT_ROUTES;
883
1313
  exports.AUTH_REPOSITORY = AUTH_REPOSITORY;
884
1314
  exports.AuthErrorCode = AuthErrorCode;
885
1315
  exports.AuthTokensDto = AuthTokensDto;
@@ -887,10 +1317,15 @@ exports.ChangePasswordDto = ChangePasswordDto;
887
1317
  exports.CurrentUser = CurrentUser;
888
1318
  exports.ForgotPasswordDto = ForgotPasswordDto;
889
1319
  exports.LoginDto = LoginDto;
1320
+ exports.MeResponseDto = MeResponseDto;
890
1321
  exports.RefreshTokenDto = RefreshTokenDto;
891
1322
  exports.RegisterAckDto = RegisterAckDto;
892
1323
  exports.RegisterDto = RegisterDto;
1324
+ exports.ResendVerificationDto = ResendVerificationDto;
893
1325
  exports.ResetPasswordDto = ResetPasswordDto;
894
1326
  exports.VerifyEmailDto = VerifyEmailDto;
1327
+ exports.buildClearRefreshTokenCookie = buildClearRefreshTokenCookie;
1328
+ exports.buildRefreshTokenCookie = buildRefreshTokenCookie;
1329
+ exports.setupAuthSwagger = setupAuthSwagger;
895
1330
  //# sourceMappingURL=index.cjs.map
896
1331
  //# sourceMappingURL=index.cjs.map