najm-auth 1.1.36 → 1.1.39

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
@@ -121,8 +121,9 @@ auth({
121
121
  database?: string // Default: 'default'
122
122
  blacklistPrefix?: string // Default: 'auth:blacklist:'
123
123
 
124
- // Registration
125
- defaultRole?: string | null // Auto-assign role to new users
124
+ // Registration
125
+ defaultRole?: string | null // Auto-assign role to new users
126
+ bcryptRounds?: number // Default: 10 (valid: 4-31)
126
127
 
127
128
  // Frontend
128
129
  frontendUrl?: string // Password reset link base URL
@@ -155,7 +156,7 @@ All routes are prefixed with `/auth` and auto-registered by the plugin.
155
156
 
156
157
  | Method | Path | Description |
157
158
  |--------|------|-------------|
158
- | `GET` | `/users` | List all users |
159
+ | `GET` | `/users?limit=50&offset=0` | List users (limit 1-100) |
159
160
  | `GET` | `/users/:id` | Get user by ID |
160
161
  | `POST` | `/users` | Create new user |
161
162
  | `PUT` | `/users/:id` | Update user |
@@ -510,8 +511,8 @@ Auth routes have built-in rate limiting to prevent brute force attacks.
510
511
  |-------|-------|--------|--------------|
511
512
  | `POST /auth/register` | 5 | 15 minutes | IP |
512
513
  | `POST /auth/login` | 5 | 15 minutes | IP |
513
- | `GET /auth/refresh` | 10 | 15 minutes | IP |
514
- | `GET /auth/logout` | 10 | 15 minutes | User ID |
514
+ | `POST /auth/refresh` | 15 | 15 minutes | Cookie fingerprint |
515
+ | `POST /auth/logout` | 10 | 15 minutes | User ID |
515
516
  | `GET /auth/me` | 30 | 1 minute | User ID |
516
517
  | `POST /auth/forgot-password` | 3 | 15 minutes | IP |
517
518
  | `POST /auth/reset-password` | 5 | 15 minutes | IP |
@@ -590,17 +591,20 @@ async resetPassword(token: string, newPassword: string) {
590
591
  }
591
592
  ```
592
593
 
593
- ### Session Management
594
-
595
- - Single refresh token per user (upsert on login)
596
- - Previous sessions invalidated on new login
597
- - Use `@RateLimit` on logout for DDoS protection
594
+ ### Session Management
595
+
596
+ - Sessions are single-device: the token table stores one refresh row per user, so a new login replaces the previous device's refresh session
597
+ - A stale refresh token presented after the 120-second rotation grace window revokes the active refresh session as reuse protection
598
+ - The signed session cookie is accepted for up to its configured TTL (5 minutes by default) without a database or revocation-cache read
599
+ - Use `@RateLimit` on logout for DDoS protection
598
600
 
599
601
  ### Token Blacklist
600
602
 
601
603
  - Built-in cache-based blacklist for immediate revocation
602
604
  - Supports Redis via `cache()` plugin configuration
603
- - Default: in-memory store (suitable for single-instance servers)
605
+ - Default: in-memory store (development/single-process only; entries are lost on restart)
606
+ - Use Redis in production when immediate revocation must survive restarts or propagate across instances
607
+ - Session-version revocation keys are cache-backed and TTL-bound to active access tokens
604
608
 
605
609
  ### Timing Attack Prevention
606
610
 
@@ -635,7 +639,8 @@ Test files include:
635
639
  - ✅ Set `FRONTEND_URL` environment variable
636
640
  - ✅ Enable HTTPS in production
637
641
  - ✅ Store secrets in environment variables (never in code)
638
- - ✅ Use Redis for token blacklist in distributed systems
642
+ - ✅ Use Redis for token blacklist/session-version revocation in production and distributed systems
643
+ - ✅ Trust forwarded IP headers only behind a known proxy; otherwise provide a custom rate-limit key generator
639
644
  - ✅ Enable rate limiting on all auth routes
640
645
  - ✅ Log authentication events for audit trails
641
646
  - ✅ Test ownership scoping rules with multi-user scenarios
@@ -0,0 +1,47 @@
1
+ import * as next_server from 'next/server';
2
+
3
+ interface AuthMiddlewareConfig {
4
+ /** Routes that require authentication (glob patterns) */
5
+ protectedRoutes?: string[];
6
+ /** Always-public routes (glob patterns) */
7
+ publicRoutes?: string[];
8
+ /** Route to redirect unauthenticated users to */
9
+ loginRoute?: string;
10
+ /** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
11
+ roleRoutes?: Record<string, string[]>;
12
+ /** Refresh token cookie name (default: 'refreshToken') */
13
+ cookieName?: string;
14
+ /** Session cookie name to clear on redirect (default: 'najm.session') */
15
+ sessionCookieName?: string;
16
+ /** URL of the verify endpoint (default: derived from request) */
17
+ verifyURL?: string;
18
+ /**
19
+ * When true, call the verify endpoint on EVERY protected route (not just
20
+ * roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
21
+ * fetch per navigation — trade latency for stronger guarantees.
22
+ */
23
+ verifyAlways?: boolean;
24
+ }
25
+ /**
26
+ * Create a Next.js middleware function that protects routes based on auth state.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // middleware.ts
31
+ * import { withAuthMiddleware } from 'najm-auth/client/server';
32
+ *
33
+ * export default withAuthMiddleware({
34
+ * protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
35
+ * publicRoutes: ['/', '/about', '/login', '/register'],
36
+ * loginRoute: '/login',
37
+ * roleRoutes: { '/admin/:path*': ['admin'] },
38
+ * });
39
+ *
40
+ * export const config = {
41
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
42
+ * };
43
+ * ```
44
+ */
45
+ declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
46
+
47
+ export { type AuthMiddlewareConfig, withAuthMiddleware };
@@ -0,0 +1,88 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/client/server/withAuthMiddleware.ts
5
+ function withAuthMiddleware(config) {
6
+ const {
7
+ protectedRoutes = [],
8
+ publicRoutes = [],
9
+ loginRoute = "/login",
10
+ roleRoutes = {},
11
+ cookieName = "refreshToken",
12
+ sessionCookieName = "najm.session",
13
+ verifyAlways = false
14
+ } = config;
15
+ return /* @__PURE__ */ __name(async function middleware(request) {
16
+ const { NextResponse } = await import("next/server");
17
+ const redirectToLogin = /* @__PURE__ */ __name((pathname2, clearCookies) => {
18
+ const loginUrl = new URL(loginRoute, request.url);
19
+ loginUrl.searchParams.set("from", pathname2);
20
+ const res = NextResponse.redirect(loginUrl);
21
+ if (clearCookies) {
22
+ res.cookies.delete(cookieName);
23
+ res.cookies.delete(sessionCookieName);
24
+ }
25
+ return res;
26
+ }, "redirectToLogin");
27
+ const url = new URL(request.url);
28
+ const pathname = url.pathname;
29
+ if (matchesAny(pathname, publicRoutes)) {
30
+ return NextResponse.next();
31
+ }
32
+ const isProtected = protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);
33
+ if (!isProtected) return NextResponse.next();
34
+ const cookie = request.headers.get("cookie") ?? "";
35
+ const hasToken = cookieRegex(cookieName).test(cookie);
36
+ if (!hasToken) {
37
+ return redirectToLogin(pathname, true);
38
+ }
39
+ const requiredRoles = findMatchingRoles(pathname, roleRoutes);
40
+ const needsVerify = verifyAlways || !!requiredRoles;
41
+ if (needsVerify) {
42
+ const verifyURL = config.verifyURL ?? `${url.origin}/api/auth/me`;
43
+ try {
44
+ const res = await fetch(verifyURL, {
45
+ headers: { "Cookie": cookie, "Accept": "application/json" }
46
+ });
47
+ if (!res.ok) {
48
+ return redirectToLogin(pathname, true);
49
+ }
50
+ if (requiredRoles) {
51
+ const body = await res.json();
52
+ const userRole = body?.data?.role;
53
+ if (!userRole || !requiredRoles.includes(userRole)) {
54
+ return new NextResponse(null, { status: 403 });
55
+ }
56
+ }
57
+ } catch {
58
+ return redirectToLogin(pathname, true);
59
+ }
60
+ }
61
+ return NextResponse.next();
62
+ }, "middleware");
63
+ }
64
+ __name(withAuthMiddleware, "withAuthMiddleware");
65
+ function matchesAny(pathname, patterns) {
66
+ return patterns.some((p) => matchPattern(pathname, p));
67
+ }
68
+ __name(matchesAny, "matchesAny");
69
+ function matchPattern(pathname, pattern) {
70
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
71
+ const regex = escaped.replace(/\/:[^/]+\*/g, "(?:/.*)?").replace(/\/\\\*$/g, "(?:/.*)?").replace(/\\\*/g, "(?:/.*)?").replace(/\//g, "\\/");
72
+ return new RegExp(`^${regex}$`).test(pathname);
73
+ }
74
+ __name(matchPattern, "matchPattern");
75
+ function cookieRegex(name) {
76
+ return new RegExp(`(?:^|;\\s*)${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=[^;]`);
77
+ }
78
+ __name(cookieRegex, "cookieRegex");
79
+ function findMatchingRoles(pathname, roleRoutes) {
80
+ for (const [pattern, roles] of Object.entries(roleRoutes)) {
81
+ if (matchPattern(pathname, pattern)) return roles;
82
+ }
83
+ return null;
84
+ }
85
+ __name(findMatchingRoles, "findMatchingRoles");
86
+ export {
87
+ withAuthMiddleware
88
+ };
@@ -1,5 +1,6 @@
1
1
  import { e as AuthUser, F as FetchClient, R as RetryConfig, N as NajmAuthClient } from '../../NajmAuthClient-D08--i69.js';
2
- import * as next_server from 'next/server';
2
+ export { withAuthMiddleware } from '../edge.js';
3
+ import 'next/server';
3
4
 
4
5
  interface GetServerSessionOptions {
5
6
  /** The URL of the /auth/me endpoint */
@@ -63,50 +64,6 @@ interface ServerClientConfig {
63
64
  */
64
65
  declare function createServerClient(config: ServerClientConfig): FetchClient;
65
66
 
66
- interface AuthMiddlewareConfig {
67
- /** Routes that require authentication (glob patterns) */
68
- protectedRoutes?: string[];
69
- /** Always-public routes (glob patterns) */
70
- publicRoutes?: string[];
71
- /** Route to redirect unauthenticated users to */
72
- loginRoute?: string;
73
- /** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
74
- roleRoutes?: Record<string, string[]>;
75
- /** Refresh token cookie name (default: 'refreshToken') */
76
- cookieName?: string;
77
- /** Session cookie name to clear on redirect (default: 'najm.session') */
78
- sessionCookieName?: string;
79
- /** URL of the verify endpoint (default: derived from request) */
80
- verifyURL?: string;
81
- /**
82
- * When true, call the verify endpoint on EVERY protected route (not just
83
- * roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
84
- * fetch per navigation — trade latency for stronger guarantees.
85
- */
86
- verifyAlways?: boolean;
87
- }
88
- /**
89
- * Create a Next.js middleware function that protects routes based on auth state.
90
- *
91
- * @example
92
- * ```ts
93
- * // middleware.ts
94
- * import { withAuthMiddleware } from 'najm-auth/client/server';
95
- *
96
- * export default withAuthMiddleware({
97
- * protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
98
- * publicRoutes: ['/', '/about', '/login', '/register'],
99
- * loginRoute: '/login',
100
- * roleRoutes: { '/admin/:path*': ['admin'] },
101
- * });
102
- *
103
- * export const config = {
104
- * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
105
- * };
106
- * ```
107
- */
108
- declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
109
-
110
67
  interface ServerSession {
111
68
  user: AuthUser;
112
69
  roles?: string[];
@@ -279,4 +236,4 @@ interface AuthKit {
279
236
  }
280
237
  declare function defineAuth(authConfig?: DefineAuthConfig): AuthKit;
281
238
 
282
- export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth, withAuthMiddleware };
239
+ export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth };
package/dist/index.d.ts CHANGED
@@ -65,6 +65,8 @@ interface AuthConfig {
65
65
  registrationMode: 'active' | 'pending';
66
66
  /** Per-account lockout settings */
67
67
  lockout: LockoutConfig;
68
+ /** Bcrypt work factor (default: 10) */
69
+ bcryptRounds: number;
68
70
  /** Session cookie cache settings */
69
71
  session: SessionCookieConfig;
70
72
  }
@@ -104,6 +106,8 @@ type AuthPluginConfig = {
104
106
  registrationMode?: 'active' | 'pending';
105
107
  /** Per-account lockout settings */
106
108
  lockout?: Partial<LockoutConfig>;
109
+ /** Bcrypt work factor (default: 10, valid range: 4-31) */
110
+ bcryptRounds?: number;
107
111
  /** Session cookie cache settings (optional — sensible defaults applied) */
108
112
  session?: Partial<SessionCookieConfig>;
109
113
  /** Optional config forwarded to validation() dependency */
@@ -139,13 +143,20 @@ interface TokenPair {
139
143
  refreshTokenExpiresAt?: number;
140
144
  }
141
145
  /**
142
- * User data structure for authentication
146
+ * User data structure for authentication.
147
+ *
148
+ * This is the minimal contract the `USER` ALS token is guaranteed to satisfy
149
+ * on every resolution path (Bearer token, refresh cookie, and the signed
150
+ * session-cookie hot path). Guards and handlers must not rely on fields
151
+ * outside this contract — the DB-backed paths include more, the session
152
+ * cookie does not.
143
153
  */
144
154
  interface AuthUser {
145
155
  id: string;
146
156
  email: string;
147
157
  name?: string | null;
148
158
  role?: string;
159
+ status?: string;
149
160
  permissions?: string[];
150
161
  }
151
162
 
@@ -343,6 +354,7 @@ declare function getAuthLocale(lang: string): Record<string, any>;
343
354
  declare const AUTH_SUPPORTED_LANGUAGES: string[];
344
355
 
345
356
  declare class EncryptionService {
357
+ private config?;
346
358
  private encryptionKey;
347
359
  constructor(encryptionKey?: string | null);
348
360
  hashPassword(password: string): Promise<string>;
@@ -352,11 +364,13 @@ declare class EncryptionService {
352
364
  }
353
365
 
354
366
  interface SessionCookieData {
367
+ /** Must satisfy the AuthUser contract — see AuthUser in ../types. */
355
368
  user: {
356
369
  id: string;
357
370
  email: string;
358
371
  name?: string | null;
359
372
  role?: string;
373
+ status?: string;
360
374
  };
361
375
  roles: string[];
362
376
  permissions: string[];
@@ -402,24 +416,25 @@ declare class UserRepository {
402
416
  private get users();
403
417
  private get roles();
404
418
  /** Shared query helper */
419
+ private queryHelper?;
405
420
  private get q();
406
- getAll(): Promise<UserWithPermissions[]>;
421
+ getAll(limit?: number, offset?: number): Promise<UserWithPermissions[]>;
407
422
  getById(id: string): Promise<UserWithPermissions | undefined>;
423
+ existsById(id: string): Promise<boolean>;
408
424
  getRawById(id: string): Promise<User | undefined>;
409
425
  getByEmail(email: string): Promise<(User & {
410
426
  role?: string | null;
411
427
  }) | undefined>;
412
428
  create(data: NewUser): Promise<User>;
413
- update(id: string, data: Partial<NewUser>): Promise<User>;
429
+ update(id: string, data: Partial<NewUser>): Promise<User | undefined>;
414
430
  updateLastLogin(id: string): Promise<User>;
415
431
  incrementFailedAttempts(id: string): Promise<User>;
416
432
  resetFailedAttempts(id: string): Promise<User>;
417
433
  setLockout(id: string, until: string): Promise<User>;
418
- delete(id: string): Promise<User>;
434
+ delete(id: string): Promise<User | undefined>;
419
435
  deleteAll(): Promise<User[]>;
420
436
  getRoleNameById(userId: string): Promise<string | null>;
421
437
  findByPhone(phone: string): Promise<UserWithPermissions | undefined>;
422
- getUserPassword(email: string): Promise<string | undefined>;
423
438
  getUserPermissions(userId: string): Promise<string[]>;
424
439
  updatePhone(id: string, phone: string): Promise<User>;
425
440
  }
@@ -441,7 +456,7 @@ declare class UserValidator {
441
456
  /**
442
457
  * Check if user exists by ID
443
458
  */
444
- checkUserExists(id: string): Promise<UserWithPermissions>;
459
+ checkUserExists(id: string): Promise<boolean>;
445
460
  /**
446
461
  * Check if user exists by email
447
462
  */
@@ -643,11 +658,16 @@ declare class UserService {
643
658
  private encryptionService;
644
659
  private i18nService;
645
660
  private authConfig;
661
+ private t;
646
662
  constructor(roleValidator: RoleValidator, roleService: RoleService, userRepository: UserRepository, userValidator: UserValidator, encryptionService: EncryptionService, i18nService: I18nService, authConfig: AuthConfig);
647
663
  private sanitizeUser;
648
664
  private sanitizeUsers;
665
+ private requireUser;
649
666
  private resolveUserRole;
650
- getAll(): Promise<SanitizedUser[]>;
667
+ getAll(options?: {
668
+ limit?: number;
669
+ offset?: number;
670
+ }): Promise<SanitizedUser[]>;
651
671
  getById(id: string): Promise<SanitizedUser>;
652
672
  getByEmail(email: string): Promise<SanitizedUser>;
653
673
  /**
@@ -663,7 +683,6 @@ declare class UserService {
663
683
  delete(id: string): Promise<SanitizedUser>;
664
684
  deleteAll(): Promise<SanitizedUser[]>;
665
685
  getRoleName(id: string): Promise<string | null>;
666
- getPassword(email: string): Promise<string | undefined>;
667
686
  updateLastLogin(id: string): Promise<void>;
668
687
  incrementFailedAttempts(id: string): Promise<number>;
669
688
  resetFailedAttempts(id: string): Promise<void>;
@@ -684,8 +703,8 @@ declare class TokenRepository {
684
703
  private schema;
685
704
  private get tokens();
686
705
  private get users();
687
- private get roles();
688
706
  /** Shared query helper */
707
+ private queryHelper?;
689
708
  private get q();
690
709
  storeRefreshToken(tokenData: {
691
710
  userId: string;
@@ -696,7 +715,15 @@ declare class TokenRepository {
696
715
  previousValidUntil?: string | null;
697
716
  previousUsedAt?: string | null;
698
717
  }): Promise<any>;
699
- markPreviousUsed(userId: string): Promise<any>;
718
+ /**
719
+ * Claim the previous-token grace slot. Conditional on BOTH the stored
720
+ * previousHash still matching the presented token AND previousUsedAt being
721
+ * NULL. Gating on the hash (not just the flag) closes the rotation race: the
722
+ * winner's rotation rewrites previousHash via storeRefreshToken, so a loser
723
+ * whose UPDATE lands after that rotation no longer matches and gets zero
724
+ * rows — exactly one caller ever claims the slot.
725
+ */
726
+ markPreviousUsed(userId: string, previousHash: string): Promise<any>;
700
727
  getRefreshTokenWithFamily(userId: string): Promise<any>;
701
728
  revokeToken(userId: string): Promise<any>;
702
729
  revokeByFamily(tokenFamily: string): Promise<any>;
@@ -723,6 +750,11 @@ declare class TokenService {
723
750
  private get blacklistPrefix();
724
751
  private get resetTokenPrefix();
725
752
  private get sessionVersionPrefix();
753
+ private sessionVersionKey;
754
+ private accessTokenTtlMs;
755
+ private expiresAt;
756
+ private getCacheValues;
757
+ private parseSessionVersion;
726
758
  extractAccessToken(authorization: string): string;
727
759
  /**
728
760
  * Verify access token and check blacklist
@@ -731,29 +763,24 @@ declare class TokenService {
731
763
  verifyAccessToken(token: string): Promise<JwtPayload>;
732
764
  verifyRefreshToken(token: string): string;
733
765
  private static readonly PREVIOUS_GRACE_SECONDS;
734
- /**
735
- * Validate a refresh token as an active session:
736
- * 1. Verify JWT signature and type claim
737
- * 2. Compare hash against current stored token
738
- * 3. If mismatch, check previous hash within short grace window
739
- * 4. Reject anything older or outside the grace window
740
- */
741
- validateRefreshSession(refreshToken: string): Promise<{
742
- userId: string;
743
- rotatedTokens?: {
744
- refreshToken: string;
745
- tokenFamily: string;
746
- };
747
- }>;
748
766
  /**
749
767
  * Read the refresh cookie and return the userId it belongs to.
750
768
  * Validates against current/previous token state with bounded recovery.
751
769
  * Throws if the cookie is missing, invalid, or outside the grace window.
770
+ *
771
+ * Intentionally side-effect-free: unlike refreshTokens(), a mismatch here
772
+ * does NOT revoke the suspect family. This is a read path (e.g. GET
773
+ * /auth/me) — a stray stale cookie on a read must not be able to destroy
774
+ * the active session. Reuse detection and revocation belong to the
775
+ * rotation path only.
752
776
  */
753
777
  resolveUserFromCookie(): Promise<string>;
754
778
  getUser(auth: string): Promise<any>;
779
+ getUserById(userId: string): Promise<any>;
755
780
  private hashToken;
756
781
  getTokenExpire(token: string): number | undefined;
782
+ decodeAccessToken(token: string): JwtPayload | null;
783
+ private signAccessToken;
757
784
  /**
758
785
  * Generate access token with unique jti for blacklist support.
759
786
  * Includes roles/permissions for client-side RBAC/PBAC.
@@ -766,10 +793,14 @@ declare class TokenService {
766
793
  /**
767
794
  * Generate refresh token with unique jti
768
795
  */
796
+ private signRefreshToken;
769
797
  generateRefreshToken(data: {
770
798
  userId: string;
771
799
  }): string;
772
800
  generateTokens(userId: string, tokenFamily?: string): Promise<{
801
+ userId: string;
802
+ roles: string[];
803
+ permissions: string[];
773
804
  accessToken: string;
774
805
  refreshToken: string;
775
806
  accessTokenExpiresAt: number;
@@ -799,6 +830,9 @@ declare class TokenService {
799
830
  * Compares provided token with hashed version in database
800
831
  */
801
832
  refreshTokens(): Promise<{
833
+ userId: string;
834
+ roles: string[];
835
+ permissions: string[];
802
836
  accessToken: string;
803
837
  refreshToken: string;
804
838
  accessTokenExpiresAt: number;
@@ -806,6 +840,8 @@ declare class TokenService {
806
840
  }>;
807
841
  revokeToken(userId: string): Promise<any>;
808
842
  invalidateUserAccessTokens(userId: string): Promise<number>;
843
+ getUserFromCookie(): Promise<any>;
844
+ private revokeSuspectRefreshFamily;
809
845
  /**
810
846
  * Logout user - blacklist access token and revoke refresh token
811
847
  */
@@ -883,6 +919,10 @@ declare const assignRoleParams: z.ZodObject<{
883
919
  userId: z.ZodString;
884
920
  roleId: z.ZodString;
885
921
  }, z.core.$strip>;
922
+ declare const userListQuery: z.ZodObject<{
923
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
924
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
925
+ }, z.core.$strip>;
886
926
  type CreateUserDto = z.infer<typeof createUserDto>;
887
927
  type UpdateUserDto = z.infer<typeof updateUserDto>;
888
928
  type UserIdParam = z.infer<typeof userIdParam>;
@@ -894,26 +934,25 @@ type LanguageParam = z.infer<typeof languageParam>;
894
934
  type EmailParam = z.infer<typeof emailParam>;
895
935
  type UserIdInParam = z.infer<typeof userIdInParam>;
896
936
  type AssignRoleParams = z.infer<typeof assignRoleParams>;
937
+ type UserListQuery = z.infer<typeof userListQuery>;
897
938
 
898
939
  declare class AuthService {
899
940
  private tokenService;
900
941
  private userService;
901
942
  private userValidator;
943
+ private encryptionService;
902
944
  private cookieManager;
903
945
  private i18nService;
904
946
  private emailService;
905
947
  private config;
906
948
  private t;
907
949
  private logger;
908
- private static readonly DUMMY_HASH;
909
- constructor(tokenService: TokenService, userService: UserService, userValidator: UserValidator, cookieManager: CookieManager, i18nService: I18nService, emailService: EmailService);
950
+ private dummyHash?;
951
+ constructor(tokenService: TokenService, userService: UserService, userValidator: UserValidator, encryptionService: EncryptionService, cookieManager: CookieManager, i18nService: I18nService, emailService: EmailService);
910
952
  private isLockoutActive;
911
953
  private nextLockoutUntil;
912
- /**
913
- * Decode JWT payload without verification (token was just generated by us).
914
- * Used to extract accurate roles/permissions for the session cookie cache.
915
- */
916
- private decodeAccessToken;
954
+ private getDummyHash;
955
+ warmupPasswordHash(): Promise<void>;
917
956
  registerUser(body: CreateUserDto): Promise<SanitizedUser>;
918
957
  loginUser(body: LoginDto): Promise<TokenPair & {
919
958
  user: SanitizedUser;
@@ -934,10 +973,7 @@ declare class AuthService {
934
973
  * fall back to cookie when no Authorization header is present.
935
974
  *
936
975
  * Refreshes the session cookie cache only when authoritative roles/permissions
937
- * are available (from the access token JWT). When called via the refresh-cookie
938
- * fallback, we cannot reliably populate permissions without a DB round-trip,
939
- * so we leave the existing cache alone — it will be refreshed by the next
940
- * login/refresh cycle.
976
+ * are available from the access token.
941
977
  */
942
978
  getMe(authorization?: string): Promise<SanitizedUser & {
943
979
  language: string;
@@ -953,7 +989,6 @@ declare class AuthService {
953
989
  }>;
954
990
  }
955
991
 
956
- declare const setConfiguredCookieName: (name: string) => void;
957
992
  declare class AuthController {
958
993
  private authService;
959
994
  constructor(authService: AuthService);
@@ -1013,6 +1048,11 @@ declare class AuthResolver {
1013
1048
  role?: string;
1014
1049
  permissions?: string[];
1015
1050
  } | false>;
1051
+ resolveFromSessionCookie(): Promise<{
1052
+ user: any;
1053
+ role?: string;
1054
+ permissions?: string[];
1055
+ } | false>;
1016
1056
  /**
1017
1057
  * Resolve the current user from the refresh cookie (cookie-only flow,
1018
1058
  * e.g. Next.js Server Components calling /auth/me with just the cookie).
@@ -1027,6 +1067,7 @@ declare class AuthResolver {
1027
1067
  permissions?: string[];
1028
1068
  } | false>;
1029
1069
  activate(): Promise<void>;
1070
+ onReady(): Promise<void>;
1030
1071
  }
1031
1072
 
1032
1073
  interface RunAsUser {
@@ -1691,6 +1732,7 @@ declare class AuthQueries {
1691
1732
  createdAt: any;
1692
1733
  updatedAt: any;
1693
1734
  };
1735
+ getUserWithPermissions(where: any): Promise<any | undefined>;
1694
1736
  /**
1695
1737
  * Get permissions for a user by their userId
1696
1738
  */
@@ -1769,7 +1811,7 @@ type RevokeTokenDto = z.infer<typeof revokeTokenDto>;
1769
1811
  declare class UserController {
1770
1812
  private userService;
1771
1813
  constructor(userService: UserService);
1772
- getUsers(): Promise<SanitizedUser[]>;
1814
+ getUsers(query: UserListQuery): Promise<SanitizedUser[]>;
1773
1815
  getLang(): Promise<{
1774
1816
  language: string;
1775
1817
  }>;
@@ -1808,6 +1850,8 @@ interface SeedUserConfig {
1808
1850
  interface AuthSeedConfig {
1809
1851
  adminEmail: string;
1810
1852
  adminPass: string;
1853
+ /** Bcrypt work factor (default: 10) */
1854
+ bcryptRounds?: number;
1811
1855
  roles?: Array<{
1812
1856
  name: string;
1813
1857
  description?: string;
@@ -1830,6 +1874,8 @@ interface SeedAuthDataConfig {
1830
1874
  adminEmail: string;
1831
1875
  /** Admin password (required) */
1832
1876
  adminPassword: string;
1877
+ /** Bcrypt work factor (default: 10) */
1878
+ bcryptRounds?: number;
1833
1879
  /** Additional users to seed (optional) */
1834
1880
  users?: SeedUserConfig[];
1835
1881
  /** Custom roles (optional - uses defaults if omitted) */
@@ -1922,4 +1968,4 @@ declare const authSeed: (config: AuthSeedConfig) => Record<string, SeedEntry>;
1922
1968
  */
1923
1969
  declare function seedAuthData(config: SeedAuthDataConfig): Promise<SeedAuthDataResult>;
1924
1970
 
1925
- export { AUTH_CONFIG, en as AUTH_EN, AUTH_LOCALES, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthPluginConfig, AuthQueries, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, type AuthUser, 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 DefineRolesOptions, type EmailParam, EncryptionService, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, NewPermission, NewRoleEntity, NewUser, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, ROLES, ROLE_GROUPS, type RefreshTokenDto, type ResetPasswordDto, 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, TOKEN_STATUS, TOKEN_TYPE, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createPermissionDto, createRoleDto, createTokenDto, createUserDto, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, isAdmin, isAdministrator, isAuth, isEmpty, isFile, isPath, join, languageParam, loginDto, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, resetPasswordDto, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, setConfiguredCookieName, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, verifyTokenDto, where };
1971
+ export { AUTH_CONFIG, en as AUTH_EN, AUTH_LOCALES, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthPluginConfig, AuthQueries, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, type AuthUser, 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 DefineRolesOptions, type EmailParam, EncryptionService, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, NewPermission, NewRoleEntity, NewUser, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, ROLES, ROLE_GROUPS, type RefreshTokenDto, type ResetPasswordDto, 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, TOKEN_STATUS, TOKEN_TYPE, 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, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createPermissionDto, createRoleDto, createTokenDto, createUserDto, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, isAdmin, isAdministrator, isAuth, isEmpty, isFile, isPath, join, languageParam, loginDto, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, resetPasswordDto, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, userListQuery, verifyTokenDto, where };