@prsm/auth 1.0.0

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.
Files changed (61) hide show
  1. package/README.md +226 -0
  2. package/index.d.ts +19 -0
  3. package/package.json +76 -0
  4. package/src/__tests__/auth.test.js +1171 -0
  5. package/src/__tests__/impersonation-test-setup.js +208 -0
  6. package/src/__tests__/impersonation.test.js +473 -0
  7. package/src/__tests__/oauth-test-setup.js +136 -0
  8. package/src/__tests__/oauth.test.js +400 -0
  9. package/src/__tests__/prsm.test.js +215 -0
  10. package/src/__tests__/test-setup.js +385 -0
  11. package/src/__tests__/totp.test.js +158 -0
  12. package/src/__tests__/two-factor-test-setup.js +331 -0
  13. package/src/__tests__/two-factor.test.js +396 -0
  14. package/src/activity-logger.js +228 -0
  15. package/src/auth-context.js +120 -0
  16. package/src/auth-functions.js +520 -0
  17. package/src/auth-manager.js +1371 -0
  18. package/src/errors.js +173 -0
  19. package/src/hooks.js +41 -0
  20. package/src/index.js +23 -0
  21. package/src/invalidation.js +166 -0
  22. package/src/middleware.js +33 -0
  23. package/src/providers/azure-provider.js +114 -0
  24. package/src/providers/base-provider.js +152 -0
  25. package/src/providers/github-provider.js +86 -0
  26. package/src/providers/google-provider.js +76 -0
  27. package/src/providers/index.js +4 -0
  28. package/src/queries.js +543 -0
  29. package/src/schema.js +261 -0
  30. package/src/totp.js +221 -0
  31. package/src/two-factor/index.js +3 -0
  32. package/src/two-factor/otp-provider.js +128 -0
  33. package/src/two-factor/totp-provider.js +98 -0
  34. package/src/two-factor/two-factor-manager.js +676 -0
  35. package/src/types.js +399 -0
  36. package/src/user-roles.js +128 -0
  37. package/src/util.js +32 -0
  38. package/types/activity-logger.d.ts +73 -0
  39. package/types/auth-context.d.ts +88 -0
  40. package/types/auth-functions.d.ts +151 -0
  41. package/types/auth-manager.d.ts +365 -0
  42. package/types/errors.d.ts +108 -0
  43. package/types/hooks.d.ts +30 -0
  44. package/types/index.d.ts +13 -0
  45. package/types/invalidation.d.ts +40 -0
  46. package/types/middleware.d.ts +11 -0
  47. package/types/providers/azure-provider.d.ts +35 -0
  48. package/types/providers/base-provider.d.ts +52 -0
  49. package/types/providers/github-provider.d.ts +29 -0
  50. package/types/providers/google-provider.d.ts +29 -0
  51. package/types/providers/index.d.ts +4 -0
  52. package/types/queries.d.ts +287 -0
  53. package/types/schema.d.ts +37 -0
  54. package/types/totp.d.ts +72 -0
  55. package/types/two-factor/index.d.ts +3 -0
  56. package/types/two-factor/otp-provider.d.ts +57 -0
  57. package/types/two-factor/totp-provider.d.ts +58 -0
  58. package/types/two-factor/two-factor-manager.d.ts +191 -0
  59. package/types/types.d.ts +688 -0
  60. package/types/user-roles.d.ts +47 -0
  61. package/types/util.d.ts +3 -0
@@ -0,0 +1,688 @@
1
+ /**
2
+ * @typedef {import("pg").Pool} Pool
3
+ * @typedef {import("express").Request} ExpressRequest
4
+ * @typedef {import("express").Response} ExpressResponse
5
+ */
6
+ /**
7
+ * @typedef {object} OAuthProviderConfig
8
+ * @property {string} clientId
9
+ * @property {string} clientSecret
10
+ * @property {string} redirectUri
11
+ */
12
+ /**
13
+ * @typedef {OAuthProviderConfig} GitHubProviderConfig
14
+ */
15
+ /**
16
+ * @typedef {OAuthProviderConfig} GoogleProviderConfig
17
+ */
18
+ /**
19
+ * @typedef {OAuthProviderConfig & { tenantId: string }} AzureProviderConfig
20
+ */
21
+ /**
22
+ * optional tracer, duck-typed against @prsm/trace - any object with a span/startSpan
23
+ * method works. auth never imports @prsm/trace; it only calls what's provided
24
+ * @typedef {object} Tracer
25
+ * @property {(name: string, fn: (span?: any) => any, attrs?: Record<string, any>) => any} [span]
26
+ * @property {(name: string, attrs?: Record<string, any>) => any} [startSpan]
27
+ */
28
+ /**
29
+ * optional limiter, duck-typed against @prsm/limit. auth consumes one unit
30
+ * before login when a limiter is provided. any @prsm/limit algorithm works -
31
+ * tokenBucket (take), slidingWindow (hit), leakyBucket (drip) - all return
32
+ * { allowed, retryAfter }
33
+ * @typedef {object} Limiter
34
+ * @property {(key: string) => Promise<{ allowed: boolean, retryAfter?: number }>} [take]
35
+ * @property {(key: string) => Promise<{ allowed: boolean, retryAfter?: number }>} [hit]
36
+ * @property {(key: string) => Promise<{ allowed: boolean, retryAfter?: number }>} [drip]
37
+ * @property {(key: string) => Promise<{ allowed: boolean, retryAfter?: number }>} [consume]
38
+ * @property {(key: string) => Promise<{ allowed: boolean, retryAfter?: number }>} [check]
39
+ */
40
+ /**
41
+ * @typedef {object} InvalidationConfig
42
+ * @property {boolean} [listen] when true, the manager opens a dedicated postgres
43
+ * LISTEN connection and drops cached sessions the instant another instance
44
+ * issues a force-logout/role/status change. falls back to poll-based resync
45
+ * when the connection or NOTIFY is unavailable (e.g. pgbouncer txn pooling)
46
+ * @property {string} [channel] notify channel name, defaults to "prsm_auth_invalidate"
47
+ */
48
+ /**
49
+ * @typedef {object} AuthConfig
50
+ * @property {Pool} db required postgres pool (pg-compatible, exposes query())
51
+ * @property {(userData: OAuthUserData) => string | number | Promise<string | number>} [createUser]
52
+ * called for new OAuth users to create your app user record and return its id;
53
+ * when omitted, OAuth users get an auto-generated uuid for user_id
54
+ * @property {string} [tablePrefix] defaults to "user_"
55
+ * @property {Record<string, number>} [roles] custom roles from defineRoles(), defaults to AuthRole
56
+ * @property {number} [minPasswordLength] defaults to 8
57
+ * @property {number} [maxPasswordLength] defaults to 64
58
+ * @property {string} [rememberDuration] defaults to "30d", parsed by @prsm/ms
59
+ * @property {string} [rememberCookieName] defaults to "remember_token"
60
+ * @property {{ domain?: string, secure?: boolean, sameSite?: "strict" | "lax" | "none" }} [cookie]
61
+ * @property {string} [resyncInterval] defaults to "30s"
62
+ * @property {{ enabled?: boolean, maxEntries?: number, actions?: AuthActivityActionType[] }} [activityLog]
63
+ * @property {{ github?: GitHubProviderConfig, google?: GoogleProviderConfig, azure?: AzureProviderConfig }} [providers]
64
+ * @property {string} [githubUserAgent] defaults to "prsm-auth"
65
+ * @property {{ enabled?: boolean, requireForOAuth?: boolean, issuer?: string, codeLength?: number, tokenExpiry?: string, totpWindow?: number, backupCodesCount?: number }} [twoFactor]
66
+ * @property {{ enabled?: boolean, defaultTtl?: string | null, maxTtl?: string, canImpersonate?: (actor: AuthAccount, target: AuthAccount) => boolean | Promise<boolean> }} [impersonation]
67
+ * @property {Tracer} [tracer] optional @prsm/trace tracer, duck-typed
68
+ * @property {Limiter} [limiter] optional @prsm/limit limiter, duck-typed
69
+ * @property {InvalidationConfig} [invalidation] optional cross-instance invalidation
70
+ */
71
+ /**
72
+ * @typedef {object} AuthAccount
73
+ * @property {number} id
74
+ * @property {string} user_id
75
+ * @property {string} email
76
+ * @property {string | null} password
77
+ * @property {boolean} verified
78
+ * @property {number} status
79
+ * @property {number} rolemask
80
+ * @property {Date | null} last_login
81
+ * @property {number} force_logout
82
+ * @property {boolean} resettable
83
+ * @property {Date} registered
84
+ */
85
+ /**
86
+ * @typedef {object} AuthProvider
87
+ * @property {number} id
88
+ * @property {number} account_id
89
+ * @property {string} provider
90
+ * @property {string} provider_id
91
+ * @property {string | null} provider_email
92
+ * @property {string | null} provider_username
93
+ * @property {string | null} provider_name
94
+ * @property {string | null} provider_avatar
95
+ * @property {Date} created_at
96
+ * @property {Date} updated_at
97
+ */
98
+ /**
99
+ * @typedef {object} OAuthUserData
100
+ * @property {string} id
101
+ * @property {string} email
102
+ * @property {string} [username]
103
+ * @property {string} [name]
104
+ * @property {string} [avatar]
105
+ */
106
+ /**
107
+ * @typedef {object} OAuthCallbackResult
108
+ * @property {boolean} isNewUser
109
+ */
110
+ /**
111
+ * @typedef {object} OAuthProvider
112
+ * @property {(state?: string, scopes?: string[]) => string} getAuthUrl
113
+ * @property {(req: ExpressRequest) => Promise<OAuthCallbackResult>} handleCallback
114
+ * @property {(req: ExpressRequest) => Promise<OAuthUserData>} getUserData
115
+ */
116
+ /**
117
+ * @typedef {object} AuthConfirmation
118
+ * @property {number} id
119
+ * @property {number} account_id
120
+ * @property {string} token
121
+ * @property {string} email
122
+ * @property {Date} expires
123
+ */
124
+ /**
125
+ * @typedef {object} AuthRemember
126
+ * @property {number} id
127
+ * @property {number} account_id
128
+ * @property {string} token
129
+ * @property {Date} expires
130
+ */
131
+ /**
132
+ * @typedef {object} AuthenticateRequestResult
133
+ * @property {AuthAccount | null} account
134
+ * @property {"session" | "remember" | null} source
135
+ */
136
+ /**
137
+ * @typedef {object} AuthReset
138
+ * @property {number} id
139
+ * @property {number} account_id
140
+ * @property {string} token
141
+ * @property {Date} expires
142
+ */
143
+ /**
144
+ * @typedef {object} AuthActivity
145
+ * @property {number} id
146
+ * @property {number | null} account_id
147
+ * @property {number | null} actor_account_id
148
+ * @property {string} action
149
+ * @property {string | null} ip_address
150
+ * @property {string | null} user_agent
151
+ * @property {string | null} browser
152
+ * @property {string | null} os
153
+ * @property {string | null} device
154
+ * @property {boolean} success
155
+ * @property {Record<string, any> | null} metadata
156
+ * @property {Date} created_at
157
+ */
158
+ /**
159
+ * @typedef {object} ImpersonationActor
160
+ * @property {number} accountId
161
+ * @property {string} userId
162
+ * @property {string} email
163
+ * @property {number} rolemask
164
+ * @property {number} forceLogout
165
+ * @property {Date} startedAt
166
+ * @property {Date} [expiresAt]
167
+ * @property {string} [reason]
168
+ */
169
+ /**
170
+ * @typedef {object} AwaitingTwoFactor
171
+ * @property {number} accountId
172
+ * @property {Date} expiresAt
173
+ * @property {boolean} remember
174
+ * @property {number[]} availableMechanisms
175
+ * @property {number[]} attemptedMechanisms
176
+ * @property {string} originalEmail
177
+ * @property {{ email?: string, sms?: string }} [selectors]
178
+ */
179
+ /**
180
+ * @typedef {object} AuthSession
181
+ * @property {boolean} loggedIn
182
+ * @property {number} accountId
183
+ * @property {string} userId
184
+ * @property {string} email
185
+ * @property {number} status
186
+ * @property {number} rolemask
187
+ * @property {boolean} remembered
188
+ * @property {Date} lastResync
189
+ * @property {Date} lastRememberCheck
190
+ * @property {number} forceLogout
191
+ * @property {boolean} verified
192
+ * @property {boolean} hasPassword
193
+ * @property {boolean} [shouldForceLogout]
194
+ * @property {ImpersonationActor} [actor]
195
+ * @property {AwaitingTwoFactor} [awaitingTwoFactor]
196
+ */
197
+ /**
198
+ * @typedef {object} ImpersonationInfo
199
+ * @property {{ accountId: number, userId: string, email: string, rolemask: number }} actor
200
+ * @property {{ accountId: number, userId: string, email: string, rolemask: number }} target
201
+ * @property {Date} startedAt
202
+ * @property {Date} [expiresAt]
203
+ * @property {string} [reason]
204
+ */
205
+ /**
206
+ * @typedef {object} StartImpersonationOptions
207
+ * @property {string} [reason]
208
+ * @property {string | number} [ttl]
209
+ */
210
+ /**
211
+ * @typedef {object} TwoFactorMethod
212
+ * @property {number} id
213
+ * @property {number} account_id
214
+ * @property {number} mechanism
215
+ * @property {string | null} secret
216
+ * @property {string[] | null} backup_codes
217
+ * @property {boolean} verified
218
+ * @property {Date} created_at
219
+ * @property {Date | null} last_used_at
220
+ */
221
+ /**
222
+ * @typedef {object} TwoFactorToken
223
+ * @property {number} id
224
+ * @property {number} account_id
225
+ * @property {number} mechanism
226
+ * @property {string} selector
227
+ * @property {string} token_hash
228
+ * @property {Date} expires_at
229
+ * @property {Date} created_at
230
+ */
231
+ /**
232
+ * @typedef {object} TwoFactorSetupResult
233
+ * @property {string} secret
234
+ * @property {string} qrCode
235
+ * @property {string[]} [backupCodes]
236
+ */
237
+ /**
238
+ * @typedef {object} TwoFactorChallenge
239
+ * @property {boolean} [totp]
240
+ * @property {{ otpValue: string, maskedContact: string }} [email]
241
+ * @property {{ otpValue: string, maskedContact: string }} [sms]
242
+ * @property {{ email?: string, sms?: string }} [selectors]
243
+ */
244
+ /**
245
+ * @typedef {(token: string) => void} TokenCallback
246
+ */
247
+ /**
248
+ * @typedef {{ accountId?: number, email?: string, userId?: string }} UserIdentifier
249
+ */
250
+ /**
251
+ * the public interface attached to req.auth by createAuthMiddleware
252
+ * @typedef {object} AuthManager
253
+ * @property {() => boolean} isLoggedIn
254
+ * @property {(email: string, password: string, remember?: boolean) => Promise<void>} login
255
+ * @property {() => Promise<void>} completeTwoFactorLogin
256
+ * @property {() => Promise<void>} logout
257
+ * @property {(email: string, password: string, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>} register
258
+ * @property {(force?: boolean) => Promise<void>} resyncSession
259
+ * @property {() => number | null} getId
260
+ * @property {() => string | null} getEmail
261
+ * @property {() => number | null} getStatus
262
+ * @property {() => boolean | null} getVerified
263
+ * @property {() => boolean | null} hasPassword
264
+ * @property {(rolemask?: number) => string[]} getRoleNames
265
+ * @property {() => string | null} getStatusName
266
+ * @property {(role: number) => Promise<boolean>} hasRole
267
+ * @property {() => Promise<boolean>} isAdmin
268
+ * @property {() => boolean} isRemembered
269
+ * @property {(newEmail: string, callback: TokenCallback) => Promise<void>} changeEmail
270
+ * @property {(token: string) => Promise<string>} confirmEmail
271
+ * @property {(token: string, remember?: boolean) => Promise<void>} confirmEmailAndLogin
272
+ * @property {(email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback) => Promise<void>} resetPassword
273
+ * @property {(token: string, password: string, logout?: boolean) => Promise<void>} confirmResetPassword
274
+ * @property {(password: string) => Promise<boolean>} verifyPassword
275
+ * @property {() => Promise<void>} logoutEverywhere
276
+ * @property {() => Promise<void>} logoutEverywhereElse
277
+ * @property {(credentials: { email: string, password: string }, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>} createUser
278
+ * @property {(identifier: UserIdentifier) => Promise<void>} deleteUserBy
279
+ * @property {(identifier: UserIdentifier, role: number) => Promise<void>} addRoleForUserBy
280
+ * @property {(identifier: UserIdentifier, role: number) => Promise<void>} removeRoleForUserBy
281
+ * @property {(identifier: UserIdentifier, role: number) => Promise<boolean>} hasRoleForUserBy
282
+ * @property {(identifier: UserIdentifier, password: string) => Promise<void>} changePasswordForUserBy
283
+ * @property {(identifier: UserIdentifier, status: number) => Promise<void>} setStatusForUserBy
284
+ * @property {(identifier: UserIdentifier, expiresAfter?: string | number | null, callback?: TokenCallback) => Promise<void>} initiatePasswordResetForUserBy
285
+ * @property {(email: string) => Promise<boolean>} userExistsByEmail
286
+ * @property {(identifier: UserIdentifier) => Promise<void>} forceLogoutForUserBy
287
+ * @property {(identifier: UserIdentifier) => Promise<void>} loginAsUserBy
288
+ * @property {(identifier: UserIdentifier, options?: StartImpersonationOptions) => Promise<void>} startImpersonation
289
+ * @property {() => Promise<void>} stopImpersonation
290
+ * @property {() => boolean} isImpersonating
291
+ * @property {() => number | null} getActorId
292
+ * @property {() => string | null} getActorEmail
293
+ * @property {() => ImpersonationInfo | null} getImpersonationInfo
294
+ * @property {{ github?: OAuthProvider, google?: OAuthProvider, azure?: OAuthProvider }} providers
295
+ * @property {import("./two-factor/two-factor-manager.js").TwoFactorManager} twoFactor
296
+ */
297
+ export const AuthStatus: Readonly<{
298
+ Normal: 0;
299
+ Archived: 1;
300
+ Banned: 2;
301
+ Locked: 3;
302
+ PendingReview: 4;
303
+ Suspended: 5;
304
+ }>;
305
+ export const AuthRole: Readonly<{
306
+ Admin: 1;
307
+ Author: 2;
308
+ Collaborator: 4;
309
+ Consultant: 8;
310
+ Consumer: 16;
311
+ Contributor: 32;
312
+ Owner: 64;
313
+ Creator: 128;
314
+ Developer: 256;
315
+ Director: 512;
316
+ Editor: 1024;
317
+ Employee: 2048;
318
+ Member: 4096;
319
+ Manager: 8192;
320
+ Moderator: 16384;
321
+ Publisher: 32768;
322
+ Reviewer: 65536;
323
+ Subscriber: 131072;
324
+ SuperAdmin: 262144;
325
+ SuperEditor: 524288;
326
+ SuperModerator: 1048576;
327
+ Translator: 2097152;
328
+ }>;
329
+ export const AuthActivityAction: Readonly<{
330
+ Login: "login";
331
+ Logout: "logout";
332
+ FailedLogin: "failed_login";
333
+ Register: "register";
334
+ EmailConfirmed: "email_confirmed";
335
+ PasswordResetRequested: "password_reset_requested";
336
+ PasswordResetCompleted: "password_reset_completed";
337
+ PasswordChanged: "password_changed";
338
+ EmailChanged: "email_changed";
339
+ RoleChanged: "role_changed";
340
+ StatusChanged: "status_changed";
341
+ ForceLogout: "force_logout";
342
+ OAuthConnected: "oauth_connected";
343
+ RememberTokenCreated: "remember_token_created";
344
+ TwoFactorSetup: "two_factor_setup";
345
+ TwoFactorVerified: "two_factor_verified";
346
+ TwoFactorFailed: "two_factor_failed";
347
+ TwoFactorDisabled: "two_factor_disabled";
348
+ BackupCodeUsed: "backup_code_used";
349
+ ImpersonationStarted: "impersonation_started";
350
+ ImpersonationStopped: "impersonation_stopped";
351
+ ImpersonationExpired: "impersonation_expired";
352
+ ImpersonationRejected: "impersonation_rejected";
353
+ }>;
354
+ /**
355
+ * @typedef {(typeof AuthActivityAction)[keyof typeof AuthActivityAction]} AuthActivityActionType
356
+ */
357
+ export const TwoFactorMechanism: Readonly<{
358
+ TOTP: 1;
359
+ EMAIL: 2;
360
+ SMS: 3;
361
+ }>;
362
+ export type Pool = import("pg").Pool;
363
+ export type ExpressRequest = import("express").Request;
364
+ export type ExpressResponse = import("express").Response;
365
+ export type OAuthProviderConfig = {
366
+ clientId: string;
367
+ clientSecret: string;
368
+ redirectUri: string;
369
+ };
370
+ export type GitHubProviderConfig = OAuthProviderConfig;
371
+ export type GoogleProviderConfig = OAuthProviderConfig;
372
+ export type AzureProviderConfig = OAuthProviderConfig & {
373
+ tenantId: string;
374
+ };
375
+ /**
376
+ * optional tracer, duck-typed against
377
+ */
378
+ export type Tracer = {
379
+ span?: (name: string, fn: (span?: any) => any, attrs?: Record<string, any>) => any;
380
+ startSpan?: (name: string, attrs?: Record<string, any>) => any;
381
+ };
382
+ /**
383
+ * optional limiter, duck-typed against
384
+ */
385
+ export type Limiter = {
386
+ take?: (key: string) => Promise<{
387
+ allowed: boolean;
388
+ retryAfter?: number;
389
+ }>;
390
+ hit?: (key: string) => Promise<{
391
+ allowed: boolean;
392
+ retryAfter?: number;
393
+ }>;
394
+ drip?: (key: string) => Promise<{
395
+ allowed: boolean;
396
+ retryAfter?: number;
397
+ }>;
398
+ consume?: (key: string) => Promise<{
399
+ allowed: boolean;
400
+ retryAfter?: number;
401
+ }>;
402
+ check?: (key: string) => Promise<{
403
+ allowed: boolean;
404
+ retryAfter?: number;
405
+ }>;
406
+ };
407
+ export type InvalidationConfig = {
408
+ /**
409
+ * when true, the manager opens a dedicated postgres
410
+ * LISTEN connection and drops cached sessions the instant another instance
411
+ * issues a force-logout/role/status change. falls back to poll-based resync
412
+ * when the connection or NOTIFY is unavailable (e.g. pgbouncer txn pooling)
413
+ */
414
+ listen?: boolean;
415
+ /**
416
+ * notify channel name, defaults to "prsm_auth_invalidate"
417
+ */
418
+ channel?: string;
419
+ };
420
+ export type AuthConfig = {
421
+ /**
422
+ * required postgres pool (pg-compatible, exposes query())
423
+ */
424
+ db: Pool;
425
+ /**
426
+ * called for new OAuth users to create your app user record and return its id;
427
+ * when omitted, OAuth users get an auto-generated uuid for user_id
428
+ */
429
+ createUser?: (userData: OAuthUserData) => string | number | Promise<string | number>;
430
+ /**
431
+ * defaults to "user_"
432
+ */
433
+ tablePrefix?: string;
434
+ /**
435
+ * custom roles from defineRoles(), defaults to AuthRole
436
+ */
437
+ roles?: Record<string, number>;
438
+ /**
439
+ * defaults to 8
440
+ */
441
+ minPasswordLength?: number;
442
+ /**
443
+ * defaults to 64
444
+ */
445
+ maxPasswordLength?: number;
446
+ /**
447
+ * defaults to "30d", parsed by
448
+ */
449
+ rememberDuration?: string;
450
+ };
451
+ export type AuthAccount = {
452
+ id: number;
453
+ user_id: string;
454
+ email: string;
455
+ password: string | null;
456
+ verified: boolean;
457
+ status: number;
458
+ rolemask: number;
459
+ last_login: Date | null;
460
+ force_logout: number;
461
+ resettable: boolean;
462
+ registered: Date;
463
+ };
464
+ export type AuthProvider = {
465
+ id: number;
466
+ account_id: number;
467
+ provider: string;
468
+ provider_id: string;
469
+ provider_email: string | null;
470
+ provider_username: string | null;
471
+ provider_name: string | null;
472
+ provider_avatar: string | null;
473
+ created_at: Date;
474
+ updated_at: Date;
475
+ };
476
+ export type OAuthUserData = {
477
+ id: string;
478
+ email: string;
479
+ username?: string;
480
+ name?: string;
481
+ avatar?: string;
482
+ };
483
+ export type OAuthCallbackResult = {
484
+ isNewUser: boolean;
485
+ };
486
+ export type OAuthProvider = {
487
+ getAuthUrl: (state?: string, scopes?: string[]) => string;
488
+ handleCallback: (req: ExpressRequest) => Promise<OAuthCallbackResult>;
489
+ getUserData: (req: ExpressRequest) => Promise<OAuthUserData>;
490
+ };
491
+ export type AuthConfirmation = {
492
+ id: number;
493
+ account_id: number;
494
+ token: string;
495
+ email: string;
496
+ expires: Date;
497
+ };
498
+ export type AuthRemember = {
499
+ id: number;
500
+ account_id: number;
501
+ token: string;
502
+ expires: Date;
503
+ };
504
+ export type AuthenticateRequestResult = {
505
+ account: AuthAccount | null;
506
+ source: "session" | "remember" | null;
507
+ };
508
+ export type AuthReset = {
509
+ id: number;
510
+ account_id: number;
511
+ token: string;
512
+ expires: Date;
513
+ };
514
+ export type AuthActivity = {
515
+ id: number;
516
+ account_id: number | null;
517
+ actor_account_id: number | null;
518
+ action: string;
519
+ ip_address: string | null;
520
+ user_agent: string | null;
521
+ browser: string | null;
522
+ os: string | null;
523
+ device: string | null;
524
+ success: boolean;
525
+ metadata: Record<string, any> | null;
526
+ created_at: Date;
527
+ };
528
+ export type ImpersonationActor = {
529
+ accountId: number;
530
+ userId: string;
531
+ email: string;
532
+ rolemask: number;
533
+ forceLogout: number;
534
+ startedAt: Date;
535
+ expiresAt?: Date;
536
+ reason?: string;
537
+ };
538
+ export type AwaitingTwoFactor = {
539
+ accountId: number;
540
+ expiresAt: Date;
541
+ remember: boolean;
542
+ availableMechanisms: number[];
543
+ attemptedMechanisms: number[];
544
+ originalEmail: string;
545
+ selectors?: {
546
+ email?: string;
547
+ sms?: string;
548
+ };
549
+ };
550
+ export type AuthSession = {
551
+ loggedIn: boolean;
552
+ accountId: number;
553
+ userId: string;
554
+ email: string;
555
+ status: number;
556
+ rolemask: number;
557
+ remembered: boolean;
558
+ lastResync: Date;
559
+ lastRememberCheck: Date;
560
+ forceLogout: number;
561
+ verified: boolean;
562
+ hasPassword: boolean;
563
+ shouldForceLogout?: boolean;
564
+ actor?: ImpersonationActor;
565
+ awaitingTwoFactor?: AwaitingTwoFactor;
566
+ };
567
+ export type ImpersonationInfo = {
568
+ actor: {
569
+ accountId: number;
570
+ userId: string;
571
+ email: string;
572
+ rolemask: number;
573
+ };
574
+ target: {
575
+ accountId: number;
576
+ userId: string;
577
+ email: string;
578
+ rolemask: number;
579
+ };
580
+ startedAt: Date;
581
+ expiresAt?: Date;
582
+ reason?: string;
583
+ };
584
+ export type StartImpersonationOptions = {
585
+ reason?: string;
586
+ ttl?: string | number;
587
+ };
588
+ export type TwoFactorMethod = {
589
+ id: number;
590
+ account_id: number;
591
+ mechanism: number;
592
+ secret: string | null;
593
+ backup_codes: string[] | null;
594
+ verified: boolean;
595
+ created_at: Date;
596
+ last_used_at: Date | null;
597
+ };
598
+ export type TwoFactorToken = {
599
+ id: number;
600
+ account_id: number;
601
+ mechanism: number;
602
+ selector: string;
603
+ token_hash: string;
604
+ expires_at: Date;
605
+ created_at: Date;
606
+ };
607
+ export type TwoFactorSetupResult = {
608
+ secret: string;
609
+ qrCode: string;
610
+ backupCodes?: string[];
611
+ };
612
+ export type TwoFactorChallenge = {
613
+ totp?: boolean;
614
+ email?: {
615
+ otpValue: string;
616
+ maskedContact: string;
617
+ };
618
+ sms?: {
619
+ otpValue: string;
620
+ maskedContact: string;
621
+ };
622
+ selectors?: {
623
+ email?: string;
624
+ sms?: string;
625
+ };
626
+ };
627
+ export type TokenCallback = (token: string) => void;
628
+ export type UserIdentifier = {
629
+ accountId?: number;
630
+ email?: string;
631
+ userId?: string;
632
+ };
633
+ /**
634
+ * the public interface attached to req.auth by createAuthMiddleware
635
+ */
636
+ export type AuthManager = {
637
+ isLoggedIn: () => boolean;
638
+ login: (email: string, password: string, remember?: boolean) => Promise<void>;
639
+ completeTwoFactorLogin: () => Promise<void>;
640
+ logout: () => Promise<void>;
641
+ register: (email: string, password: string, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;
642
+ resyncSession: (force?: boolean) => Promise<void>;
643
+ getId: () => number | null;
644
+ getEmail: () => string | null;
645
+ getStatus: () => number | null;
646
+ getVerified: () => boolean | null;
647
+ hasPassword: () => boolean | null;
648
+ getRoleNames: (rolemask?: number) => string[];
649
+ getStatusName: () => string | null;
650
+ hasRole: (role: number) => Promise<boolean>;
651
+ isAdmin: () => Promise<boolean>;
652
+ isRemembered: () => boolean;
653
+ changeEmail: (newEmail: string, callback: TokenCallback) => Promise<void>;
654
+ confirmEmail: (token: string) => Promise<string>;
655
+ confirmEmailAndLogin: (token: string, remember?: boolean) => Promise<void>;
656
+ resetPassword: (email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback) => Promise<void>;
657
+ confirmResetPassword: (token: string, password: string, logout?: boolean) => Promise<void>;
658
+ verifyPassword: (password: string) => Promise<boolean>;
659
+ logoutEverywhere: () => Promise<void>;
660
+ logoutEverywhereElse: () => Promise<void>;
661
+ createUser: (credentials: {
662
+ email: string;
663
+ password: string;
664
+ }, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;
665
+ deleteUserBy: (identifier: UserIdentifier) => Promise<void>;
666
+ addRoleForUserBy: (identifier: UserIdentifier, role: number) => Promise<void>;
667
+ removeRoleForUserBy: (identifier: UserIdentifier, role: number) => Promise<void>;
668
+ hasRoleForUserBy: (identifier: UserIdentifier, role: number) => Promise<boolean>;
669
+ changePasswordForUserBy: (identifier: UserIdentifier, password: string) => Promise<void>;
670
+ setStatusForUserBy: (identifier: UserIdentifier, status: number) => Promise<void>;
671
+ initiatePasswordResetForUserBy: (identifier: UserIdentifier, expiresAfter?: string | number | null, callback?: TokenCallback) => Promise<void>;
672
+ userExistsByEmail: (email: string) => Promise<boolean>;
673
+ forceLogoutForUserBy: (identifier: UserIdentifier) => Promise<void>;
674
+ loginAsUserBy: (identifier: UserIdentifier) => Promise<void>;
675
+ startImpersonation: (identifier: UserIdentifier, options?: StartImpersonationOptions) => Promise<void>;
676
+ stopImpersonation: () => Promise<void>;
677
+ isImpersonating: () => boolean;
678
+ getActorId: () => number | null;
679
+ getActorEmail: () => string | null;
680
+ getImpersonationInfo: () => ImpersonationInfo | null;
681
+ providers: {
682
+ github?: OAuthProvider;
683
+ google?: OAuthProvider;
684
+ azure?: OAuthProvider;
685
+ };
686
+ twoFactor: import("./two-factor/two-factor-manager.js").TwoFactorManager;
687
+ };
688
+ export type AuthActivityActionType = (typeof AuthActivityAction)[keyof typeof AuthActivityAction];