@ministerjs/auth 2.0.2 → 3.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/dist/nestjs.js CHANGED
@@ -32,15 +32,174 @@ __export(nestjs_exports, {
32
32
  AUTH_DRIVER: () => AUTH_DRIVER,
33
33
  AuthController: () => AuthController,
34
34
  AuthModule: () => AuthModule,
35
- JwtPrismaCookieAuthDriver: () => JwtPrismaCookieAuthDriver
35
+ InMemoryLockoutStore: () => InMemoryLockoutStore,
36
+ InMemoryRefreshTokenStore: () => InMemoryRefreshTokenStore,
37
+ JwtAuthGuard: () => JwtAuthGuard,
38
+ JwtPrismaCookieAuthDriver: () => JwtPrismaCookieAuthDriver,
39
+ ROLES_KEY: () => ROLES_KEY,
40
+ Roles: () => Roles,
41
+ RolesGuard: () => RolesGuard
36
42
  });
37
43
  module.exports = __toCommonJS(nestjs_exports);
38
44
 
39
45
  // src/nestjs/token.ts
40
46
  var AUTH_DRIVER = Symbol("AUTH_DRIVER");
41
47
 
42
- // src/nestjs/AuthController.ts
48
+ // src/nestjs/stores.ts
49
+ var InMemoryLockoutStore = class {
50
+ constructor(windowMs) {
51
+ this.windowMs = windowMs;
52
+ }
53
+ entries = /* @__PURE__ */ new Map();
54
+ async recordFailure(key) {
55
+ const now = Date.now();
56
+ const entry = this.entries.get(key);
57
+ if (!entry || now - entry.firstFailure > this.windowMs) {
58
+ this.entries.set(key, { count: 1, firstFailure: now });
59
+ } else {
60
+ entry.count++;
61
+ }
62
+ }
63
+ async getFailures(key) {
64
+ const entry = this.entries.get(key);
65
+ if (!entry) return 0;
66
+ if (Date.now() - entry.firstFailure > this.windowMs) {
67
+ this.entries.delete(key);
68
+ return 0;
69
+ }
70
+ return entry.count;
71
+ }
72
+ async reset(key) {
73
+ this.entries.delete(key);
74
+ }
75
+ };
76
+ var InMemoryRefreshTokenStore = class {
77
+ tokens = /* @__PURE__ */ new Map();
78
+ userJtis = /* @__PURE__ */ new Map();
79
+ async save(jti, userId, expiresAt) {
80
+ this.tokens.set(jti, { userId, expiresAt });
81
+ let jtis = this.userJtis.get(userId);
82
+ if (!jtis) {
83
+ jtis = /* @__PURE__ */ new Set();
84
+ this.userJtis.set(userId, jtis);
85
+ }
86
+ jtis.add(jti);
87
+ }
88
+ async find(jti) {
89
+ const entry = this.tokens.get(jti);
90
+ if (!entry) return null;
91
+ if (entry.expiresAt.getTime() < Date.now()) {
92
+ this.tokens.delete(jti);
93
+ return null;
94
+ }
95
+ return entry;
96
+ }
97
+ async revoke(jti) {
98
+ const entry = this.tokens.get(jti);
99
+ if (entry) {
100
+ this.userJtis.get(entry.userId)?.delete(jti);
101
+ }
102
+ this.tokens.delete(jti);
103
+ }
104
+ async revokeAll(userId) {
105
+ const jtis = this.userJtis.get(userId);
106
+ if (jtis) {
107
+ for (const jti of jtis) {
108
+ this.tokens.delete(jti);
109
+ }
110
+ this.userJtis.delete(userId);
111
+ }
112
+ }
113
+ };
114
+
115
+ // src/nestjs/rbac.ts
43
116
  var import_common = require("@nestjs/common");
117
+ var ROLES_KEY = "ministerjs:roles";
118
+ var Roles = (...roles) => (0, import_common.SetMetadata)(ROLES_KEY, roles);
119
+
120
+ // src/nestjs/guards/JwtAuthGuard.ts
121
+ var import_common2 = require("@nestjs/common");
122
+ var import_jsonwebtoken = require("jsonwebtoken");
123
+ var JwtAuthGuard = class {
124
+ jwtSecret;
125
+ cookieName;
126
+ csrfEnabled;
127
+ constructor(options) {
128
+ this.jwtSecret = options.jwtSecret;
129
+ this.cookieName = options.cookieName ?? "auth_token";
130
+ this.csrfEnabled = options.csrfEnabled ?? false;
131
+ }
132
+ canActivate(context) {
133
+ const request = context.switchToHttp().getRequest();
134
+ const token = this.extractToken(request);
135
+ if (!token) {
136
+ throw new import_common2.UnauthorizedException("No token provided");
137
+ }
138
+ let payload;
139
+ try {
140
+ payload = (0, import_jsonwebtoken.verify)(token, this.jwtSecret, {
141
+ algorithms: ["HS256"]
142
+ });
143
+ } catch {
144
+ throw new import_common2.UnauthorizedException("Invalid token");
145
+ }
146
+ if (this.csrfEnabled) {
147
+ this.validateCsrf(request);
148
+ }
149
+ request.user = {
150
+ id: payload.sub,
151
+ roles: payload.roles ?? []
152
+ };
153
+ return true;
154
+ }
155
+ extractToken(request) {
156
+ const fromCookie = request.cookies?.[this.cookieName];
157
+ if (fromCookie) return fromCookie;
158
+ const authHeader = request.headers.authorization;
159
+ if (authHeader?.startsWith("Bearer ")) return authHeader.slice(7);
160
+ return void 0;
161
+ }
162
+ validateCsrf(request) {
163
+ const headerToken = request.headers["x-csrf-token"];
164
+ const cookieToken = request.cookies?.["csrf_token"];
165
+ if (!headerToken || headerToken !== cookieToken) {
166
+ throw new import_common2.UnauthorizedException("CSRF token mismatch");
167
+ }
168
+ }
169
+ };
170
+ JwtAuthGuard = __decorateClass([
171
+ (0, import_common2.Injectable)()
172
+ ], JwtAuthGuard);
173
+
174
+ // src/nestjs/guards/RolesGuard.ts
175
+ var import_common3 = require("@nestjs/common");
176
+ var RolesGuard = class {
177
+ constructor(reflector) {
178
+ this.reflector = reflector;
179
+ }
180
+ canActivate(context) {
181
+ const required = this.reflector.getAllAndOverride(ROLES_KEY, [
182
+ context.getHandler(),
183
+ context.getClass()
184
+ ]);
185
+ if (!required?.length) return true;
186
+ const request = context.switchToHttp().getRequest();
187
+ if (!request.user) {
188
+ throw new import_common3.ForbiddenException("Not authenticated");
189
+ }
190
+ const hasRole = required.some((r) => request.user.roles.includes(r));
191
+ if (!hasRole) {
192
+ throw new import_common3.ForbiddenException("Insufficient permissions");
193
+ }
194
+ return true;
195
+ }
196
+ };
197
+ RolesGuard = __decorateClass([
198
+ (0, import_common3.Injectable)()
199
+ ], RolesGuard);
200
+
201
+ // src/nestjs/AuthController.ts
202
+ var import_common4 = require("@nestjs/common");
44
203
  var AuthController = class {
45
204
  constructor(driver) {
46
205
  this.driver = driver;
@@ -52,7 +211,17 @@ var AuthController = class {
52
211
  async checkIn(request, response) {
53
212
  const user = await this.driver.checkIn(request, response);
54
213
  if (!user) {
55
- throw new import_common.UnauthorizedException("Not authenticated");
214
+ throw new import_common4.UnauthorizedException("Not authenticated");
215
+ }
216
+ return { message: "ok", data: user };
217
+ }
218
+ async refresh(request, response) {
219
+ if (!this.driver.refresh) {
220
+ throw new import_common4.UnauthorizedException("Refresh not supported");
221
+ }
222
+ const user = await this.driver.refresh(request, response);
223
+ if (!user) {
224
+ throw new import_common4.UnauthorizedException("Invalid refresh token");
56
225
  }
57
226
  return { message: "ok", data: user };
58
227
  }
@@ -62,31 +231,37 @@ var AuthController = class {
62
231
  }
63
232
  };
64
233
  __decorateClass([
65
- (0, import_common.Post)("/login"),
66
- (0, import_common.HttpCode)(200),
67
- __decorateParam(0, (0, import_common.Body)()),
68
- __decorateParam(1, (0, import_common.Req)()),
69
- __decorateParam(2, (0, import_common.Res)({ passthrough: true }))
234
+ (0, import_common4.Post)("/login"),
235
+ (0, import_common4.HttpCode)(200),
236
+ __decorateParam(0, (0, import_common4.Body)()),
237
+ __decorateParam(1, (0, import_common4.Req)()),
238
+ __decorateParam(2, (0, import_common4.Res)({ passthrough: true }))
70
239
  ], AuthController.prototype, "login", 1);
71
240
  __decorateClass([
72
- (0, import_common.Post)("/checkin"),
73
- (0, import_common.HttpCode)(200),
74
- __decorateParam(0, (0, import_common.Req)()),
75
- __decorateParam(1, (0, import_common.Res)({ passthrough: true }))
241
+ (0, import_common4.Post)("/checkin"),
242
+ (0, import_common4.HttpCode)(200),
243
+ __decorateParam(0, (0, import_common4.Req)()),
244
+ __decorateParam(1, (0, import_common4.Res)({ passthrough: true }))
76
245
  ], AuthController.prototype, "checkIn", 1);
77
246
  __decorateClass([
78
- (0, import_common.Post)("/logout"),
79
- (0, import_common.HttpCode)(200),
80
- __decorateParam(0, (0, import_common.Req)()),
81
- __decorateParam(1, (0, import_common.Res)({ passthrough: true }))
247
+ (0, import_common4.Post)("/refresh"),
248
+ (0, import_common4.HttpCode)(200),
249
+ __decorateParam(0, (0, import_common4.Req)()),
250
+ __decorateParam(1, (0, import_common4.Res)({ passthrough: true }))
251
+ ], AuthController.prototype, "refresh", 1);
252
+ __decorateClass([
253
+ (0, import_common4.Post)("/logout"),
254
+ (0, import_common4.HttpCode)(200),
255
+ __decorateParam(0, (0, import_common4.Req)()),
256
+ __decorateParam(1, (0, import_common4.Res)({ passthrough: true }))
82
257
  ], AuthController.prototype, "logout", 1);
83
258
  AuthController = __decorateClass([
84
- (0, import_common.Controller)(),
85
- __decorateParam(0, (0, import_common.Inject)(AUTH_DRIVER))
259
+ (0, import_common4.Controller)(),
260
+ __decorateParam(0, (0, import_common4.Inject)(AUTH_DRIVER))
86
261
  ], AuthController);
87
262
 
88
263
  // src/nestjs/AuthModule.ts
89
- var import_common2 = require("@nestjs/common");
264
+ var import_common5 = require("@nestjs/common");
90
265
  var AuthModule = class {
91
266
  static register(options) {
92
267
  const driverProvider = this.normalizeDriverProvider(options.driver);
@@ -111,6 +286,9 @@ var AuthModule = class {
111
286
  exports: [driverProvider]
112
287
  };
113
288
  }
289
+ static createGuard(options) {
290
+ return new JwtAuthGuard(options);
291
+ }
114
292
  static normalizeDriverProvider(driver) {
115
293
  if (typeof driver === "function") {
116
294
  return { provide: AUTH_DRIVER, useClass: driver };
@@ -132,16 +310,30 @@ var AuthModule = class {
132
310
  }
133
311
  };
134
312
  AuthModule = __decorateClass([
135
- (0, import_common2.Module)({})
313
+ (0, import_common5.Module)({})
136
314
  ], AuthModule);
137
315
 
138
316
  // src/nestjs/JwtPrismaCookieAuthDriver.ts
139
- var import_common3 = require("@nestjs/common");
140
- var import_jsonwebtoken = require("jsonwebtoken");
317
+ var import_node_crypto = require("crypto");
318
+ var import_common6 = require("@nestjs/common");
319
+ var import_jsonwebtoken2 = require("jsonwebtoken");
320
+ var DURATION_UNITS = {
321
+ s: 1e3,
322
+ m: 6e4,
323
+ h: 36e5,
324
+ d: 864e5
325
+ };
326
+ function parseDuration(value) {
327
+ const match = value.match(/^(\d+)\s*([smhd])$/);
328
+ if (!match) return 7 * 864e5;
329
+ return parseInt(match[1], 10) * DURATION_UNITS[match[2]];
330
+ }
331
+ var isProduction = process.env.NODE_ENV === "production";
141
332
  var defaultCookieOptions = {
142
333
  httpOnly: true,
143
334
  sameSite: "lax",
144
- path: "/"
335
+ path: "/",
336
+ secure: isProduction
145
337
  };
146
338
  var JwtPrismaCookieAuthDriver = class {
147
339
  prismaModel;
@@ -154,13 +346,23 @@ var JwtPrismaCookieAuthDriver = class {
154
346
  cookieOptions;
155
347
  comparePassword;
156
348
  transformUser;
349
+ csrf;
350
+ onAudit;
351
+ onRateLimitCheck;
352
+ lockoutStore;
353
+ lockoutMaxAttempts;
354
+ refreshTokenEnabled;
355
+ refreshTokenCookieName;
356
+ refreshTokenExpiresIn;
357
+ refreshTokenStore;
157
358
  constructor(options) {
158
- this.prismaModel = options.prisma[options.modelName];
159
- if (!this.prismaModel) {
359
+ const model = options.prisma[options.modelName];
360
+ if (!model) {
160
361
  throw new Error(
161
362
  `Model "${options.modelName}" n\xE3o encontrado no PrismaClient.`
162
363
  );
163
364
  }
365
+ this.prismaModel = model;
164
366
  this.identifierField = options.identifierField ?? "email";
165
367
  this.passwordField = options.passwordField ?? "password";
166
368
  this.idField = options.idField ?? "id";
@@ -171,34 +373,107 @@ var JwtPrismaCookieAuthDriver = class {
171
373
  ...defaultCookieOptions,
172
374
  ...options.cookieOptions ?? {}
173
375
  };
174
- this.comparePassword = options.comparePassword ?? ((provided, stored) => String(stored) === provided);
376
+ this.comparePassword = options.comparePassword;
175
377
  this.transformUser = options.transformUser ?? ((user) => {
176
378
  const clone = { ...user };
177
379
  delete clone[this.passwordField];
178
380
  return clone;
179
381
  });
382
+ this.csrf = options.csrf ?? false;
383
+ this.onAudit = options.onAudit;
384
+ this.onRateLimitCheck = options.onRateLimitCheck;
385
+ if (options.lockout) {
386
+ const windowMs = options.lockout.windowMs ?? 15 * 60 * 1e3;
387
+ this.lockoutMaxAttempts = options.lockout.maxAttempts ?? 5;
388
+ this.lockoutStore = options.lockout.store ?? new InMemoryLockoutStore(windowMs);
389
+ } else {
390
+ this.lockoutMaxAttempts = 0;
391
+ }
392
+ if (options.refreshToken?.enabled) {
393
+ this.refreshTokenEnabled = true;
394
+ this.refreshTokenCookieName = options.refreshToken.cookieName ?? "refresh_token";
395
+ this.refreshTokenExpiresIn = options.refreshToken.expiresIn ?? "30d";
396
+ this.refreshTokenStore = options.refreshToken.store ?? new InMemoryRefreshTokenStore();
397
+ } else {
398
+ this.refreshTokenEnabled = false;
399
+ this.refreshTokenCookieName = "refresh_token";
400
+ this.refreshTokenExpiresIn = "30d";
401
+ }
180
402
  }
181
- async login(payload, _req, res) {
403
+ async login(payload, req, res) {
182
404
  const identifier = payload[this.identifierField];
405
+ const ip = req.ip ?? req.socket?.remoteAddress ?? "unknown";
406
+ if (this.onRateLimitCheck) {
407
+ const allowed = await this.onRateLimitCheck(ip, identifier);
408
+ if (!allowed) {
409
+ await this.emitAudit({
410
+ action: "login",
411
+ ip,
412
+ success: false,
413
+ metadata: { reason: "rate_limited" }
414
+ });
415
+ throw new import_common6.UnauthorizedException("Too many requests");
416
+ }
417
+ }
418
+ if (this.lockoutStore) {
419
+ const failures = await this.lockoutStore.getFailures(identifier);
420
+ if (failures >= this.lockoutMaxAttempts) {
421
+ await this.emitAudit({
422
+ action: "lockout",
423
+ ip,
424
+ success: false,
425
+ metadata: { identifier }
426
+ });
427
+ throw new import_common6.UnauthorizedException("Invalid credentials");
428
+ }
429
+ }
183
430
  const user = await this.prismaModel.findUnique({
184
431
  where: { [this.identifierField]: identifier }
185
432
  });
186
433
  if (!user) {
187
- throw new import_common3.UnauthorizedException("Invalid credentials");
434
+ await this.lockoutStore?.recordFailure(identifier);
435
+ await this.emitAudit({ action: "login", ip, success: false });
436
+ throw new import_common6.UnauthorizedException("Invalid credentials");
188
437
  }
189
438
  const ok = await this.comparePassword(
190
439
  payload[this.passwordField],
191
440
  user[this.passwordField]
192
441
  );
193
442
  if (!ok) {
194
- throw new import_common3.UnauthorizedException("Invalid credentials");
443
+ await this.lockoutStore?.recordFailure(identifier);
444
+ await this.emitAudit({
445
+ action: "login",
446
+ userId: String(user[this.idField]),
447
+ ip,
448
+ success: false
449
+ });
450
+ throw new import_common6.UnauthorizedException("Invalid credentials");
195
451
  }
196
- const token = (0, import_jsonwebtoken.sign)(
452
+ await this.lockoutStore?.reset(identifier);
453
+ const token = (0, import_jsonwebtoken2.sign)(
197
454
  { sub: user[this.idField] },
198
455
  this.jwtSecret,
199
- { expiresIn: this.jwtExpiresIn }
456
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
200
457
  );
201
458
  res.cookie(this.cookieName, token, this.cookieOptions);
459
+ if (this.refreshTokenEnabled && this.refreshTokenStore) {
460
+ await this.issueRefreshToken(String(user[this.idField]), res);
461
+ }
462
+ if (this.csrf) {
463
+ const csrfToken = (0, import_node_crypto.randomBytes)(32).toString("hex");
464
+ res.cookie("csrf_token", csrfToken, {
465
+ httpOnly: false,
466
+ sameSite: this.cookieOptions.sameSite,
467
+ path: "/",
468
+ secure: this.cookieOptions.secure
469
+ });
470
+ }
471
+ await this.emitAudit({
472
+ action: "login",
473
+ userId: String(user[this.idField]),
474
+ ip,
475
+ success: true
476
+ });
202
477
  return this.transformUser(user);
203
478
  }
204
479
  async checkIn(req, res) {
@@ -208,7 +483,9 @@ var JwtPrismaCookieAuthDriver = class {
208
483
  }
209
484
  let payload;
210
485
  try {
211
- payload = (0, import_jsonwebtoken.verify)(token, this.jwtSecret);
486
+ payload = (0, import_jsonwebtoken2.verify)(token, this.jwtSecret, {
487
+ algorithms: ["HS256"]
488
+ });
212
489
  } catch {
213
490
  return null;
214
491
  }
@@ -218,14 +495,125 @@ var JwtPrismaCookieAuthDriver = class {
218
495
  if (!user) {
219
496
  return null;
220
497
  }
221
- res.cookie(this.cookieName, token, this.cookieOptions);
498
+ const newToken = (0, import_jsonwebtoken2.sign)(
499
+ { sub: payload.sub },
500
+ this.jwtSecret,
501
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
502
+ );
503
+ res.cookie(this.cookieName, newToken, this.cookieOptions);
504
+ await this.emitAudit({
505
+ action: "checkin",
506
+ userId: String(payload.sub),
507
+ ip: req.ip ?? req.socket?.remoteAddress,
508
+ success: true
509
+ });
222
510
  return this.transformUser(user);
223
511
  }
224
- async logout(_req, res) {
512
+ async logout(req, res) {
225
513
  res.clearCookie(this.cookieName, {
226
514
  ...this.cookieOptions,
227
515
  maxAge: 0
228
516
  });
517
+ if (this.refreshTokenEnabled) {
518
+ const refreshCookie = req.cookies?.[this.refreshTokenCookieName];
519
+ if (refreshCookie && this.refreshTokenStore) {
520
+ try {
521
+ const payload = (0, import_jsonwebtoken2.verify)(refreshCookie, this.jwtSecret, {
522
+ algorithms: ["HS256"]
523
+ });
524
+ if (payload.jti) {
525
+ await this.refreshTokenStore.revokeAll(String(payload.sub));
526
+ }
527
+ } catch {
528
+ }
529
+ }
530
+ res.clearCookie(this.refreshTokenCookieName, {
531
+ ...this.cookieOptions,
532
+ maxAge: 0
533
+ });
534
+ }
535
+ if (this.csrf) {
536
+ res.clearCookie("csrf_token", { path: "/", maxAge: 0 });
537
+ }
538
+ await this.emitAudit({
539
+ action: "logout",
540
+ ip: req.ip ?? req.socket?.remoteAddress,
541
+ success: true
542
+ });
543
+ }
544
+ async refresh(req, res) {
545
+ if (!this.refreshTokenEnabled || !this.refreshTokenStore) {
546
+ return null;
547
+ }
548
+ const refreshCookie = req.cookies?.[this.refreshTokenCookieName];
549
+ if (!refreshCookie) {
550
+ return null;
551
+ }
552
+ let payload;
553
+ try {
554
+ payload = (0, import_jsonwebtoken2.verify)(refreshCookie, this.jwtSecret, {
555
+ algorithms: ["HS256"]
556
+ });
557
+ } catch {
558
+ return null;
559
+ }
560
+ if (!payload.jti) {
561
+ return null;
562
+ }
563
+ const stored = await this.refreshTokenStore.find(payload.jti);
564
+ if (!stored) {
565
+ return null;
566
+ }
567
+ await this.refreshTokenStore.revoke(payload.jti);
568
+ const userId = String(payload.sub);
569
+ const user = await this.prismaModel.findUnique({
570
+ where: { [this.idField]: userId }
571
+ });
572
+ if (!user) {
573
+ return null;
574
+ }
575
+ const accessToken = (0, import_jsonwebtoken2.sign)(
576
+ { sub: userId },
577
+ this.jwtSecret,
578
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
579
+ );
580
+ res.cookie(this.cookieName, accessToken, this.cookieOptions);
581
+ await this.issueRefreshToken(userId, res);
582
+ if (this.csrf) {
583
+ const csrfToken = (0, import_node_crypto.randomBytes)(32).toString("hex");
584
+ res.cookie("csrf_token", csrfToken, {
585
+ httpOnly: false,
586
+ sameSite: this.cookieOptions.sameSite,
587
+ path: "/",
588
+ secure: this.cookieOptions.secure
589
+ });
590
+ }
591
+ await this.emitAudit({
592
+ action: "refresh",
593
+ userId,
594
+ ip: req.ip ?? req.socket?.remoteAddress,
595
+ success: true
596
+ });
597
+ return this.transformUser(user);
598
+ }
599
+ async issueRefreshToken(userId, res) {
600
+ const jti = (0, import_node_crypto.randomUUID)();
601
+ const expiresInMs = typeof this.refreshTokenExpiresIn === "number" ? this.refreshTokenExpiresIn * 1e3 : parseDuration(this.refreshTokenExpiresIn);
602
+ const expiresAt = new Date(Date.now() + expiresInMs);
603
+ const refreshToken = (0, import_jsonwebtoken2.sign)(
604
+ { sub: userId, jti },
605
+ this.jwtSecret,
606
+ { expiresIn: this.refreshTokenExpiresIn, algorithm: "HS256" }
607
+ );
608
+ await this.refreshTokenStore.save(jti, userId, expiresAt);
609
+ res.cookie(this.refreshTokenCookieName, refreshToken, {
610
+ ...this.cookieOptions,
611
+ path: "/"
612
+ });
613
+ }
614
+ async emitAudit(partial) {
615
+ if (!this.onAudit) return;
616
+ await this.onAudit({ ...partial, timestamp: /* @__PURE__ */ new Date() });
229
617
  }
230
618
  };
231
619
  // Annotate the CommonJS export names for ESM import in node:
@@ -233,5 +621,11 @@ var JwtPrismaCookieAuthDriver = class {
233
621
  AUTH_DRIVER,
234
622
  AuthController,
235
623
  AuthModule,
236
- JwtPrismaCookieAuthDriver
624
+ InMemoryLockoutStore,
625
+ InMemoryRefreshTokenStore,
626
+ JwtAuthGuard,
627
+ JwtPrismaCookieAuthDriver,
628
+ ROLES_KEY,
629
+ Roles,
630
+ RolesGuard
237
631
  });