@vunexa/lixa 0.1.6-alpha.14 → 0.1.6-alpha.16

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.
@@ -25,6 +25,31 @@ export declare interface AccountHandler {
25
25
  accountStorage?: AccountStorage;
26
26
  }
27
27
 
28
+ /**
29
+ * Thrown when a login attempt matches an existing user under another provider,
30
+ * requiring step-up verification (e.g. password or original provider login) before linking.
31
+ *
32
+ * @public
33
+ */
34
+ export declare class AccountLinkingChallengeRequiredError extends LixaError {
35
+ readonly challengeToken: string;
36
+ readonly email: string;
37
+ readonly incomingProvider: string;
38
+ readonly incomingProviderUserId?: string | undefined;
39
+ readonly existingUserId: string;
40
+ readonly existingProviders: string[];
41
+ readonly hasPassword: boolean;
42
+ constructor(message: string, details: {
43
+ challengeToken: string;
44
+ email: string;
45
+ incomingProvider: string;
46
+ incomingProviderUserId?: string | undefined;
47
+ existingUserId: string;
48
+ existingProviders: string[];
49
+ hasPassword: boolean;
50
+ });
51
+ }
52
+
28
53
  /**
29
54
  * Account linking settings for Lixa.
30
55
  *
@@ -52,7 +77,7 @@ export declare interface AccountLinkingConfig {
52
77
  *
53
78
  * @public
54
79
  */
55
- export declare type AccountLinkingMode = AccountLinkingStrategy | "AUTO_LINK_BY_VERIFIED_EMAIL" | "ISOLATED" | "linkByEmail" | "separate";
80
+ export declare type AccountLinkingMode = AccountLinkingStrategy | "AUTO_LINK_BY_VERIFIED_EMAIL" | "ISOLATED" | "STEP_UP_VERIFICATION" | "linkByEmail" | "separate" | "stepUp";
56
81
 
57
82
  /**
58
83
  * Main configuration object for Lixa.
@@ -129,7 +154,18 @@ export declare enum AccountLinkingStrategy {
129
154
  /** Automatically merge identities matching the same verified primary email address */
130
155
  AUTO_LINK_BY_VERIFIED_EMAIL = "AUTO_LINK_BY_VERIFIED_EMAIL",
131
156
  /** Keep identity profiles isolated per provider (no automatic account merging) */
132
- ISOLATED = "ISOLATED"
157
+ ISOLATED = "ISOLATED",
158
+ /** Require password or original provider step-up verification before linking secondary accounts */
159
+ STEP_UP_VERIFICATION = "STEP_UP_VERIFICATION"
160
+ }
161
+
162
+ /**
163
+ * Thrown when a user's account has not been verified/confirmed yet.
164
+ *
165
+ * @public
166
+ */
167
+ export declare class AccountNotVerifiedError extends LixaError {
168
+ constructor(identifier?: string, details?: Record<string, unknown>);
133
169
  }
134
170
 
135
171
  /**
@@ -142,6 +178,11 @@ export declare interface AccountStorage {
142
178
  getAccount(userId: string, provider: string): Promise<LinkedAccount | null>;
143
179
  getUserAccounts(userId: string): Promise<Record<string, LinkedAccount>>;
144
180
  deleteAccount(userId: string, provider: string): Promise<void>;
181
+ findAccountsByEmail?(email: string): Promise<Array<{
182
+ userId: string;
183
+ provider: string;
184
+ account: LinkedAccount;
185
+ }>>;
145
186
  }
146
187
 
147
188
  /**
@@ -159,6 +200,8 @@ export declare class AccountUnlinkError extends LixaError {
159
200
  * @public
160
201
  */
161
202
  export declare interface ChangePasswordParams {
203
+ /** Target identity provider name when using CompositeIdentityProvider */
204
+ provider?: string | undefined;
162
205
  /** Username (optional if identifier or userId is provided) */
163
206
  username?: string | undefined;
164
207
  /** Primary identifier (optional if username or userId is provided) */
@@ -197,6 +240,83 @@ export declare function clearSessionCookie(options?: CookieOptions): CookiePaylo
197
240
  */
198
241
  export declare function clearStateCookie(options?: CookieOptions): CookiePayload;
199
242
 
243
+ /**
244
+ * Composite Identity Provider that aggregates multiple child IIdentityProvider instances
245
+ * and OAuth 2.0 / OIDC provider configurations under a single unified identityProvider.
246
+ *
247
+ * @remarks
248
+ * Eliminates the need for separate `federatedOAuthProviders` configuration in Lixa.
249
+ * Provides compile-time autocompletion of configured provider names.
250
+ * Routing is strictly explicit: uses `params.provider` if provided, or `defaultProvider`.
251
+ * No silent fallbacks or guesswork.
252
+ *
253
+ * @public
254
+ */
255
+ export declare class CompositeIdentityProvider<TProviders extends Record<string, IIdentityProvider> = Record<string, IIdentityProvider>, TOAuthProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> implements IIdentityProvider {
256
+ readonly name: string;
257
+ readonly providers: TProviders;
258
+ readonly defaultProvider?: (keyof TProviders & string) | undefined;
259
+ readonly oauthProviders?: TOAuthProviders | undefined;
260
+ constructor(options: CompositeIdentityProviderOptions<TProviders, TOAuthProviders>);
261
+ /**
262
+ * Resolves the target child provider based on explicit parameter or defaultProvider.
263
+ * Throws an error immediately if the provider cannot be resolved or does not exist.
264
+ */
265
+ selectProvider(providerName?: string): IIdentityProvider;
266
+ /**
267
+ * Returns all OAuth / OIDC provider configurations aggregated across this composite provider
268
+ * and any child providers exposing `getOAuthProviders()` or `getProviders()`.
269
+ */
270
+ getProviders(): Record<string, ProviderConfig>;
271
+ signUp(params: SignUpParams): Promise<UserIdentity>;
272
+ signIn(params: SignInParams): Promise<IdentityAuthResult>;
273
+ verifyCredentials(params: VerifyCredentialsParams): Promise<UserIdentity | null>;
274
+ changePassword(params: ChangePasswordParams): Promise<boolean>;
275
+ forgotPassword(params: ForgotPasswordParams): Promise<ForgotPasswordResult>;
276
+ confirmPasswordReset(params: ConfirmPasswordResetParams): Promise<boolean>;
277
+ confirmSignUp(params: ConfirmSignUpParams): Promise<boolean>;
278
+ resendConfirmationCode(params: ResendConfirmationCodeParams): Promise<ResendConfirmationCodeResult>;
279
+ getUserById(id: string, providerName?: string): Promise<UserIdentity | null>;
280
+ getUserByIdentifier(identifier: string, providerName?: string): Promise<UserIdentity | null>;
281
+ deleteUser(id: string, providerName?: string): Promise<void>;
282
+ }
283
+
284
+ /**
285
+ * Options for initializing a CompositeIdentityProvider.
286
+ *
287
+ * @public
288
+ */
289
+ export declare interface CompositeIdentityProviderOptions<TProviders extends Record<string, IIdentityProvider> = Record<string, IIdentityProvider>, TOAuthProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
290
+ /**
291
+ * Record of child identity providers keyed by unique provider names.
292
+ * e.g. `{ cognito: new CognitoIdentityProvider(...), okta: new OktaIdentityProvider(...) }`
293
+ */
294
+ providers: TProviders;
295
+ /**
296
+ * Default provider key to use when a request does not explicitly pass a `provider` parameter.
297
+ */
298
+ defaultProvider?: (keyof TProviders & string) | undefined;
299
+ /**
300
+ * Record of OAuth 2.0 / OIDC provider configurations (Google, GitHub, etc.)
301
+ * to register alongside these identity providers.
302
+ */
303
+ oauthProviders?: TOAuthProviders | undefined;
304
+ }
305
+
306
+ /**
307
+ * Inferred key of identity providers configured in a CompositeIdentityProvider.
308
+ *
309
+ * @public
310
+ */
311
+ export declare type ConfiguredIdentityKey<TIdentity> = TIdentity extends CompositeIdentityProvider<infer TProviders, any> ? (keyof TProviders & string) : string;
312
+
313
+ /**
314
+ * Inferred key of OAuth / OIDC providers configured in a CompositeIdentityProvider or inline providers.
315
+ *
316
+ * @public
317
+ */
318
+ export declare type ConfiguredOAuthKey<TIdentity = unknown, TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> = TIdentity extends CompositeIdentityProvider<any, infer TOAuth> ? (keyof TOAuth & string) | (keyof TProviders & string) : keyof TProviders & string;
319
+
200
320
  /**
201
321
  * Type representing the keys of configured providers
202
322
  */
@@ -208,6 +328,8 @@ declare type ConfiguredProviderKey<TProviders extends Record<string, ProviderCon
208
328
  * @public
209
329
  */
210
330
  export declare interface ConfirmPasswordResetParams {
331
+ /** Target identity provider name when using CompositeIdentityProvider */
332
+ provider?: string | undefined;
211
333
  /** Username or email of the account */
212
334
  identifier: string;
213
335
  /** Verification code (e.g. 6-digit OTP from email/SMS) or reset token */
@@ -222,6 +344,8 @@ export declare interface ConfirmPasswordResetParams {
222
344
  * @public
223
345
  */
224
346
  export declare interface ConfirmSignUpParams {
347
+ /** Target identity provider name when using CompositeIdentityProvider */
348
+ provider?: string | undefined;
225
349
  /** Username or email of the account to confirm */
226
350
  identifier: string;
227
351
  /** Verification code (e.g. 6-digit OTP from email/SMS) */
@@ -425,6 +549,13 @@ export declare interface CredentialsConfig {
425
549
  * @default 86400 (24 hours)
426
550
  */
427
551
  sessionTtlSeconds?: number | undefined;
552
+ /**
553
+ * Whether identity verification (e.g. email confirmation code) is required before persisting credentials to storage.
554
+ * When true, signUp creates a pending registration without writing to storage, requiring confirmSignUp() to activate.
555
+ *
556
+ * @default false
557
+ */
558
+ requireVerification?: boolean | undefined;
428
559
  }
429
560
 
430
561
  /**
@@ -473,6 +604,20 @@ export declare class CredentialsManager {
473
604
  * @returns True if password was successfully updated
474
605
  */
475
606
  changePassword(params: ChangePasswordParams): Promise<boolean>;
607
+ /**
608
+ * Sets a password for a user who doesn't have one yet (e.g. SSO-first users),
609
+ * or updates an existing password without requiring the old one.
610
+ * This should only be called from an authenticated context (user already verified their identity via SSO).
611
+ *
612
+ * @param params - userId and newPassword
613
+ * @returns True if password was successfully set
614
+ */
615
+ setPassword(params: {
616
+ userId: string;
617
+ newPassword: string;
618
+ identifier?: string;
619
+ email?: string;
620
+ }): Promise<boolean>;
476
621
  /**
477
622
  * Finds a user by ID and returns safe user data.
478
623
  */
@@ -551,6 +696,12 @@ export declare interface CredentialsStorage {
551
696
  * @param username - Username string
552
697
  */
553
698
  findUserByUsername?(username: string): Promise<UserCredentials | null>;
699
+ /**
700
+ * Optional helper to find user directly by email address.
701
+ *
702
+ * @param email - Verified email address
703
+ */
704
+ findUserByEmail?(email: string): Promise<UserCredentials | null>;
554
705
  }
555
706
 
556
707
  /**
@@ -660,6 +811,8 @@ export declare function fetchUserInfo(accessToken: string, userInfoEndpoint: str
660
811
  * @public
661
812
  */
662
813
  export declare interface ForgotPasswordParams {
814
+ /** Target identity provider name when using CompositeIdentityProvider */
815
+ provider?: string | undefined;
663
816
  /** Username or email of the account requesting a password reset */
664
817
  identifier: string;
665
818
  /** Optional custom client metadata or redirect URL */
@@ -693,7 +846,9 @@ export declare namespace identity {
693
846
  ResendConfirmationCodeResult,
694
847
  IIdentityProvider,
695
848
  IdentityConfig,
696
- SelfManagedIdentityProvider
849
+ SelfManagedIdentityProvider,
850
+ CompositeIdentityProviderOptions,
851
+ CompositeIdentityProvider
697
852
  }
698
853
  }
699
854
 
@@ -1074,10 +1229,16 @@ export declare interface LinkedAccount {
1074
1229
  providerUserId?: string | undefined;
1075
1230
  /** User email for this provider */
1076
1231
  email?: string | undefined;
1077
- /** OAuth access token for this provider */
1078
- accessToken: string;
1079
- /** Full raw token response from provider */
1080
- raw: OAuthTokenResponse;
1232
+ /**
1233
+ * Optional OAuth access token for this provider.
1234
+ * @deprecated Authentication tokens belong strictly to session.token / session.raw for that session alone. Resource tokens belong in ConnectedResource / user_resources.
1235
+ */
1236
+ accessToken?: string | undefined;
1237
+ /**
1238
+ * Optional raw token response from provider.
1239
+ * @deprecated Authentication tokens belong strictly to session.token / session.raw for that session alone. Resource tokens belong in ConnectedResource / user_resources.
1240
+ */
1241
+ raw?: OAuthTokenResponse | undefined;
1081
1242
  /** Unix timestamp in milliseconds when account was linked */
1082
1243
  linkedAt: number;
1083
1244
  }
@@ -1134,7 +1295,7 @@ export declare interface LinkedAccount {
1134
1295
  *
1135
1296
  * @public
1136
1297
  */
1137
- export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
1298
+ export declare class Lixa<TIdentity extends IIdentityProvider | IdentityConfig = IIdentityProvider | IdentityConfig, TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
1138
1299
  private static DEFAULT_PROVIDERS;
1139
1300
  private static CONFIGURED_PROVIDERS;
1140
1301
  private localStateHandler;
@@ -1144,6 +1305,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1144
1305
  private userResourceStore;
1145
1306
  private userAccountStore;
1146
1307
  private refreshMutexes;
1308
+ private linkingChallenges;
1147
1309
  private identityProvider?;
1148
1310
  private credentialsManager?;
1149
1311
  private config;
@@ -1166,7 +1328,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1166
1328
  * @throws Error when provider implementation is missing required properties
1167
1329
  * @throws Error when provider is not available and no inline implementation is provided
1168
1330
  */
1169
- constructor(config: LixaConfig<TProviders>);
1331
+ constructor(config: LixaConfig<TIdentity, TProviders>);
1170
1332
  /**
1171
1333
  * Validates that a provider configuration has all required credentials.
1172
1334
  *
@@ -1207,7 +1369,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1207
1369
  * }
1208
1370
  * ```
1209
1371
  */
1210
- isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TProviders>;
1372
+ isProviderConfigured<T extends string>(provider: T): provider is T & (ConfiguredOAuthKey<TIdentity, TProviders> | ConfiguredProviderKey<TProviders>);
1211
1373
  /**
1212
1374
  * Gets a provider implementation by name.
1213
1375
  * Resolution priority: inline custom provider \> default providers \> legacy registry
@@ -1388,7 +1550,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1388
1550
  * res.redirect(authUrl);
1389
1551
  * ```
1390
1552
  */
1391
- getAuthUrl(provider: ConfiguredProviderKey<TProviders> | string, state?: string): Promise<string>;
1553
+ getAuthUrl(provider: ConfiguredOAuthKey<TIdentity, TProviders> | string, state?: string): Promise<string>;
1392
1554
  /**
1393
1555
  * Restricts primary authentication scopes strictly to AuthN identity scopes unless allowNonAuthScopes is true.
1394
1556
  */
@@ -1413,7 +1575,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1413
1575
  * ```
1414
1576
  */
1415
1577
  handleCallback({ provider, code, state, sessionId, }: {
1416
- provider: ConfiguredProviderKey<TProviders> | string;
1578
+ provider: ConfiguredOAuthKey<TIdentity, TProviders> | string;
1417
1579
  code: string;
1418
1580
  state?: string;
1419
1581
  sessionId?: string;
@@ -1438,6 +1600,38 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1438
1600
  * @returns Promise resolving to true on successful unlink
1439
1601
  */
1440
1602
  unlinkAccount(sessionId: string, providerToUnlink: string): Promise<boolean>;
1603
+ /**
1604
+ * Confirms a pending account linking step-up challenge using the user's password.
1605
+ * On successful verification, links the pending provider to the existing account and creates a session.
1606
+ *
1607
+ * @param params - challengeToken and password
1608
+ * @returns Session ID, Session, and User identity
1609
+ * @throws InvalidStateError if challenge is invalid or expired
1610
+ * @throws InvalidCredentialsError if password verification fails
1611
+ */
1612
+ confirmLinkingWithPassword(params: {
1613
+ challengeToken: string;
1614
+ password: string;
1615
+ }): Promise<{
1616
+ sessionId: string;
1617
+ session: Session;
1618
+ user?: any;
1619
+ }>;
1620
+ /**
1621
+ * Sets a password for an SSO-authenticated user who doesn't have one yet.
1622
+ * Must be called from an authenticated context (user has active session proving identity).
1623
+ *
1624
+ * @param params - userId, newPassword, optional identifier and email
1625
+ * @returns True if password was set successfully
1626
+ * @throws IdentityNotConfiguredError if no identity provider configured
1627
+ * @throws WeakPasswordError if password doesn't meet policy
1628
+ */
1629
+ setPassword(params: {
1630
+ userId: string;
1631
+ newPassword: string;
1632
+ identifier?: string;
1633
+ email?: string;
1634
+ }): Promise<boolean>;
1441
1635
  /**
1442
1636
  * Generates an authorization URL for connecting a resource provider (AuthZ) post-login.
1443
1637
  *
@@ -1451,19 +1645,21 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1451
1645
  */
1452
1646
  getResourceAuthUrl(params: {
1453
1647
  sessionId: string;
1454
- provider: ConfiguredProviderKey<TProviders> | string;
1648
+ provider: ConfiguredOAuthKey<TIdentity, TProviders> | string;
1455
1649
  scopes?: string[];
1456
1650
  state?: string;
1457
1651
  prompt?: string;
1652
+ authorizationParams?: Record<string, string>;
1458
1653
  extraConfig?: Record<string, string>;
1459
1654
  }): Promise<string>;
1460
1655
  private getUserKeyFromSession;
1656
+ private sanitizeIdentityForStorage;
1461
1657
  /**
1462
1658
  * Handles the OAuth callback for a connected resource provider and stores resource tokens bound to user account.
1463
1659
  */
1464
1660
  handleResourceCallback(params: {
1465
1661
  sessionId: string;
1466
- provider: ConfiguredProviderKey<TProviders> | string;
1662
+ provider: ConfiguredOAuthKey<TIdentity, TProviders> | string;
1467
1663
  code: string;
1468
1664
  state?: string;
1469
1665
  scopes?: string[];
@@ -1474,7 +1670,7 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1474
1670
  * @param provider - Provider name (e.g. 'github', 'google')
1475
1671
  * @returns Array of configured resource scopes, or undefined if not configured
1476
1672
  */
1477
- getResourceScopes(provider: ConfiguredProviderKey<TProviders> | string): string[] | undefined;
1673
+ getResourceScopes(provider: ConfiguredOAuthKey<TIdentity, TProviders> | string): string[] | undefined;
1478
1674
  /**
1479
1675
  * Returns the resolved session cookie name.
1480
1676
  * Dynamically reflects any changes to the active identity provider.
@@ -1536,6 +1732,13 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1536
1732
  * Retrieves active session details from session storage.
1537
1733
  */
1538
1734
  fetchSessionInfo(sessionId: string): Promise<Session | null>;
1735
+ /**
1736
+ * Retrieves all linked accounts for a user from account storage.
1737
+ *
1738
+ * @param userIdOrSessionId - User ID, email, or active session ID
1739
+ * @returns Record mapping provider name to linked account metadata
1740
+ */
1741
+ getUserAccounts(userIdOrSessionId: string): Promise<Record<string, LinkedAccount>>;
1539
1742
  /**
1540
1743
  * Deletes a session from session storage (e.g. on logout).
1541
1744
  *
@@ -1579,90 +1782,109 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1579
1782
  * @throws UserAlreadyExistsError if identifier is already registered
1580
1783
  * @throws IdentityNotConfiguredError if identity authentication is not configured
1581
1784
  */
1582
- signUp(params: SignUpParams): Promise<SignUpResult>;
1785
+ signUp(params: SignUpParams & {
1786
+ provider?: ConfiguredIdentityKey<TIdentity>;
1787
+ }): Promise<SignUpResult>;
1583
1788
  /**
1584
- * Authenticates a user with credentials via the configured identity provider (Self-Managed DB, Cognito, Auth0, Okta).
1789
+ * Authenticates a user with credentials via the configured identity provider (Self-Managed DB, Cognito, Auth0, Okta, or Composite).
1585
1790
  * Creates an active session and automatically links with existing sessions when AUTO_LINK_BY_VERIFIED_EMAIL is configured.
1586
1791
  *
1587
- * @param params - Sign-in parameters (identifier, password)
1792
+ * @param params - Sign-in parameters (identifier, password, optional provider)
1588
1793
  * @returns Authenticated user, session ID, and session object
1589
1794
  * @throws InvalidCredentialsError if authentication fails
1590
1795
  * @throws IdentityNotConfiguredError if identity authentication is not configured
1591
1796
  */
1592
- signIn(params: SignInParams): Promise<SignInResult>;
1797
+ signIn(params: SignInParams & {
1798
+ provider?: ConfiguredIdentityKey<TIdentity>;
1799
+ }): Promise<SignInResult>;
1593
1800
  /**
1594
1801
  * Verifies username/email and password credentials without generating a session.
1595
1802
  *
1596
- * @param params - Verification parameters (identifier, password)
1803
+ * @param params - Verification parameters (identifier, password, optional provider)
1597
1804
  * @returns User credentials/identity or null if invalid
1598
1805
  * @throws IdentityNotConfiguredError if identity auth is not configured
1599
1806
  */
1600
- verifyCredentials(params: VerifyCredentialsParams): Promise<UserIdentity | null>;
1807
+ verifyCredentials(params: VerifyCredentialsParams & {
1808
+ provider?: ConfiguredIdentityKey<TIdentity>;
1809
+ }): Promise<UserIdentity | null>;
1601
1810
  /**
1602
1811
  * Updates a user's password after verifying the current password and enforcing policy on the new password.
1603
1812
  *
1604
- * @param params - Change password parameters (userId/identifier, oldPassword, newPassword)
1813
+ * @param params - Change password parameters (userId/identifier, oldPassword, newPassword, optional provider)
1605
1814
  * @returns True if password was updated successfully
1606
1815
  * @throws UserNotFoundError if user is not found
1607
1816
  * @throws InvalidCredentialsError if current password is incorrect
1608
1817
  * @throws WeakPasswordError if new password does not meet policy requirements
1609
1818
  * @throws IdentityNotConfiguredError if identity auth is not configured
1610
1819
  */
1611
- changePassword(params: ChangePasswordParams): Promise<boolean>;
1820
+ changePassword(params: ChangePasswordParams & {
1821
+ provider?: ConfiguredIdentityKey<TIdentity>;
1822
+ }): Promise<boolean>;
1612
1823
  /**
1613
1824
  * Initiates a password reset (forgot password flow) through the configured identity provider.
1614
1825
  *
1615
- * @param params - Forgot password parameters (identifier, optional metadata)
1826
+ * @param params - Forgot password parameters (identifier, optional metadata, optional provider)
1616
1827
  * @returns ForgotPasswordResult indicating status and delivery medium (email/SMS)
1617
1828
  * @throws IdentityNotConfiguredError if identity auth is not configured
1618
1829
  */
1619
- forgotPassword(params: ForgotPasswordParams): Promise<ForgotPasswordResult>;
1830
+ forgotPassword(params: ForgotPasswordParams & {
1831
+ provider?: ConfiguredIdentityKey<TIdentity>;
1832
+ }): Promise<ForgotPasswordResult>;
1620
1833
  /**
1621
1834
  * Confirms a password reset using a verification code / token and sets the new password.
1622
1835
  *
1623
- * @param params - Verification code, identifier, and new password
1836
+ * @param params - Verification code, identifier, new password, and optional provider
1624
1837
  * @returns True if password reset was successfully confirmed
1625
1838
  * @throws IdentityNotConfiguredError if identity auth is not configured
1626
1839
  */
1627
- confirmPasswordReset(params: ConfirmPasswordResetParams): Promise<boolean>;
1840
+ confirmPasswordReset(params: ConfirmPasswordResetParams & {
1841
+ provider?: ConfiguredIdentityKey<TIdentity>;
1842
+ }): Promise<boolean>;
1628
1843
  /**
1629
1844
  * Confirms user account registration using a verification code.
1630
1845
  *
1631
- * @param params - Verification parameters including identifier and confirmationCode
1846
+ * @param params - Verification parameters including identifier, confirmationCode, and optional provider
1632
1847
  * @returns True if confirmation was successful
1633
1848
  * @throws IdentityNotConfiguredError if identity auth is not configured
1634
1849
  * @throws IdentityProviderError if identity provider does not support confirmation
1635
1850
  */
1636
- confirmSignUp(params: ConfirmSignUpParams): Promise<boolean>;
1851
+ confirmSignUp(params: ConfirmSignUpParams & {
1852
+ provider?: ConfiguredIdentityKey<TIdentity>;
1853
+ }): Promise<boolean>;
1637
1854
  /**
1638
1855
  * Resends the sign up confirmation code to the user.
1639
1856
  *
1640
- * @param params - Resend parameters including user identifier
1857
+ * @param params - Resend parameters including user identifier and optional provider
1641
1858
  * @returns Details about the code delivery (medium, destination)
1642
1859
  * @throws IdentityNotConfiguredError if identity auth is not configured
1643
1860
  * @throws IdentityProviderError if identity provider does not support resending codes
1644
1861
  */
1645
- resendConfirmationCode(params: ResendConfirmationCodeParams): Promise<ResendConfirmationCodeResult>;
1862
+ resendConfirmationCode(params: ResendConfirmationCodeParams & {
1863
+ provider?: ConfiguredIdentityKey<TIdentity>;
1864
+ }): Promise<ResendConfirmationCodeResult>;
1646
1865
  /**
1647
1866
  * Retrieves a user by their unique ID from the configured identity provider.
1648
1867
  *
1649
1868
  * @param id - Unique user ID
1869
+ * @param provider - Optional provider key when using CompositeIdentityProvider
1650
1870
  * @returns UserIdentity or null if not found
1651
1871
  */
1652
- getUserById(id: string): Promise<UserIdentity | null>;
1872
+ getUserById(id: string, provider?: ConfiguredIdentityKey<TIdentity>): Promise<UserIdentity | null>;
1653
1873
  /**
1654
1874
  * Retrieves a user by their identifier (username or email) from the configured identity provider.
1655
1875
  *
1656
1876
  * @param identifier - Username or email string
1877
+ * @param provider - Optional provider key when using CompositeIdentityProvider
1657
1878
  * @returns UserIdentity or null if not found
1658
1879
  */
1659
- getUserByIdentifier(identifier: string): Promise<UserIdentity | null>;
1880
+ getUserByIdentifier(identifier: string, provider?: ConfiguredIdentityKey<TIdentity>): Promise<UserIdentity | null>;
1660
1881
  /**
1661
1882
  * Deletes a user account from the configured identity provider.
1662
1883
  *
1663
1884
  * @param id - Unique user ID
1885
+ * @param provider - Optional provider key when using CompositeIdentityProvider
1664
1886
  */
1665
- deleteUser(id: string): Promise<void>;
1887
+ deleteUser(id: string, provider?: ConfiguredIdentityKey<TIdentity>): Promise<void>;
1666
1888
  private findProviderByType;
1667
1889
  }
1668
1890
 
@@ -1672,37 +1894,36 @@ export declare class Lixa<TProviders extends Record<string, ProviderConfig> = Re
1672
1894
  *
1673
1895
  * @public
1674
1896
  */
1675
- export declare interface LixaConfig<TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
1897
+ export declare interface LixaConfig<TIdentity extends IIdentityProvider | IdentityConfig = IIdentityProvider | IdentityConfig, TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
1676
1898
  /**
1677
- * Map of federated OAuth 2.0 / OIDC provider names to their configurations (Google, GitHub, etc.)
1678
- * that federate with and work alongside the primary identityProvider.
1679
- * Provider names will be available for autocomplete in getAuthUrl() and handleCallback().
1680
- */
1681
- federatedOAuthProviders?: TProviders;
1682
- /**
1683
- * Alias for {@link LixaConfig.federatedOAuthProviders}.
1684
- */
1685
- providers?: TProviders;
1686
- /**
1687
- * Primary Identity Provider configuration (Self-Managed Database, AWS Cognito, Auth0, Okta, or custom IIdentityProvider).
1688
- *
1689
- * @example
1690
- * Self-managed with Prisma:
1691
- * ```typescript
1692
- * identityProvider: { storage: prismaAdapter.credentialsStorage }
1693
- * ```
1899
+ * Primary Identity Provider configuration (Self-Managed Database, AWS Cognito, Auth0, Okta,
1900
+ * or a CompositeIdentityProvider combining multiple backends and OAuth providers).
1694
1901
  *
1695
1902
  * @example
1696
- * AWS Cognito:
1903
+ * Composite Identity Provider:
1697
1904
  * ```typescript
1698
- * identityProvider: new CognitoIdentityProvider({ userPoolId: '...', clientId: '...', region: 'us-east-1' })
1905
+ * identityProvider: new CompositeIdentityProvider({
1906
+ * defaultProvider: 'cognito',
1907
+ * providers: {
1908
+ * cognito: new CognitoIdentityProvider(...),
1909
+ * 'self-managed': new SelfManagedIdentityProvider(...)
1910
+ * },
1911
+ * oauthProviders: {
1912
+ * google: { provider: new GoogleProvider(), ... }
1913
+ * }
1914
+ * })
1699
1915
  * ```
1700
1916
  */
1701
- identityProvider?: IIdentityProvider | IdentityConfig;
1917
+ identityProvider?: TIdentity;
1702
1918
  /**
1703
1919
  * Alias for {@link LixaConfig.identityProvider}.
1704
1920
  */
1705
- identity?: IIdentityProvider | IdentityConfig;
1921
+ identity?: TIdentity;
1922
+ /**
1923
+ * Direct OAuth 2.0 / OIDC provider configurations (Google, GitHub, etc.).
1924
+ * When using CompositeIdentityProvider, OAuth providers can also be defined in its `oauthProviders` field.
1925
+ */
1926
+ providers?: TProviders;
1706
1927
  /**
1707
1928
  * Credentials (username and password) authentication configuration.
1708
1929
  * Automatically maps to a SelfManagedIdentityProvider.
@@ -1983,38 +2204,6 @@ export declare class Pbkdf2PasswordHasher implements IPasswordHasher {
1983
2204
 
1984
2205
  /**
1985
2206
  * Configuration for an OAuth provider instance.
1986
- *
1987
- * @remarks
1988
- * For built-in providers (google, github), just provide credentials.
1989
- * For custom providers, include the provider implementation.
1990
- *
1991
- * The provider field uses a discriminated union to ensure type safety:
1992
- * - When omitted or undefined: assumes a built-in provider
1993
- * - When provided: must be a valid IProvider implementation
1994
- *
1995
- * @example
1996
- * Built-in provider configuration:
1997
- * ```typescript
1998
- * {
1999
- * clientId: 'your-client-id',
2000
- * clientSecret: 'your-client-secret',
2001
- * redirectUri: 'https://app.com/callback',
2002
- * scopes: ['openid', 'email']
2003
- * }
2004
- * ```
2005
- *
2006
- * @example
2007
- * Custom provider configuration:
2008
- * ```typescript
2009
- * {
2010
- * provider: new CustomProvider(),
2011
- * clientId: 'your-client-id',
2012
- * clientSecret: 'your-client-secret',
2013
- * redirectUri: 'https://app.com/callback',
2014
- * scopes: ['read:user']
2015
- * }
2016
- * ```
2017
- *
2018
2207
  * @public
2019
2208
  */
2020
2209
  export declare type ProviderConfig = {
@@ -2024,11 +2213,25 @@ export declare type ProviderConfig = {
2024
2213
  clientSecret: string;
2025
2214
  /** The redirect URI registered with the provider */
2026
2215
  redirectUri: string;
2027
- /** Array of OAuth scopes to request. If omitted, uses provider default identity scopes. */
2028
- scopes?: string[];
2029
2216
  /**
2030
- * Default scopes requested when connecting this provider as a third-party resource (AuthZ).
2031
- * Used automatically by getResourceAuthUrl() and handleResourceCallback() if not overridden at runtime.
2217
+ * Explicit scopes for authentication and post-login resource authorization.
2218
+ * Can be configured as `{ auth: [...], resource: [...] }` or a shorthand `string[]` for auth scopes.
2219
+ *
2220
+ * @example
2221
+ * ```typescript
2222
+ * scopes: {
2223
+ * auth: ["openid", "email", "profile"],
2224
+ * resource: ["https://www.googleapis.com/auth/drive.readonly"],
2225
+ * }
2226
+ * ```
2227
+ */
2228
+ scopes?: ScopesConfig | string[];
2229
+ /**
2230
+ * Flat alias for authentication scopes (AuthN).
2231
+ */
2232
+ authScopes?: string[];
2233
+ /**
2234
+ * Flat alias for post-authentication resource authorization scopes (AuthZ).
2032
2235
  */
2033
2236
  resourceScopes?: string[];
2034
2237
  /**
@@ -2037,7 +2240,11 @@ export declare type ProviderConfig = {
2037
2240
  * clean AuthN vs AuthZ separation.
2038
2241
  */
2039
2242
  allowNonAuthScopes?: boolean;
2040
- /** Additional provider-specific configuration parameters */
2243
+ /**
2244
+ * Custom query parameters passed to the OAuth authorization endpoint (e.g. `{ identity_provider: "Google" }`).
2245
+ */
2246
+ authorizationParams?: Record<string, string>;
2247
+ /** Additional provider-specific configuration parameters (alias for authorizationParams) */
2041
2248
  extraConfig?: Record<string, string>;
2042
2249
  } & ({
2043
2250
  provider?: never;
@@ -2089,6 +2296,8 @@ export declare class RefreshTokenError extends LixaError {
2089
2296
  * @public
2090
2297
  */
2091
2298
  export declare interface ResendConfirmationCodeParams {
2299
+ /** Target identity provider name when using CompositeIdentityProvider */
2300
+ provider?: string | undefined;
2092
2301
  /** Username or email of the account */
2093
2302
  identifier: string;
2094
2303
  }
@@ -2169,6 +2378,60 @@ export declare type SafeLixaConfig<TProviders extends Record<string, ProviderCon
2169
2378
  providers: TProviders;
2170
2379
  };
2171
2380
 
2381
+ /**
2382
+ * Configuration for an OAuth provider instance.
2383
+ *
2384
+ * @remarks
2385
+ * For built-in providers (google, github), just provide credentials.
2386
+ * For custom providers, include the provider implementation.
2387
+ *
2388
+ * The provider field uses a discriminated union to ensure type safety:
2389
+ * - When omitted or undefined: assumes a built-in provider
2390
+ * - When provided: must be a valid IProvider implementation
2391
+ *
2392
+ * @example
2393
+ * Built-in provider configuration:
2394
+ * ```typescript
2395
+ * {
2396
+ * clientId: 'your-client-id',
2397
+ * clientSecret: 'your-client-secret',
2398
+ * redirectUri: 'https://app.com/callback',
2399
+ * scopes: ['openid', 'email']
2400
+ * }
2401
+ * ```
2402
+ *
2403
+ * @example
2404
+ * Custom provider configuration:
2405
+ * ```typescript
2406
+ * {
2407
+ * provider: new CustomProvider(),
2408
+ * clientId: 'your-client-id',
2409
+ * clientSecret: 'your-client-secret',
2410
+ * redirectUri: 'https://app.com/callback',
2411
+ * scopes: ['read:user']
2412
+ * }
2413
+ * ```
2414
+ *
2415
+ * @public
2416
+ */
2417
+ /**
2418
+ * Scopes configuration explicitly partitioned into authentication and resource authorization.
2419
+ *
2420
+ * @public
2421
+ */
2422
+ export declare interface ScopesConfig {
2423
+ /**
2424
+ * Explicit identity scopes requested during primary authentication (AuthN) (e.g. ['openid', 'email', 'profile']).
2425
+ * If omitted, uses the provider's default identity scopes.
2426
+ */
2427
+ auth?: string[];
2428
+ /**
2429
+ * Explicit permission scopes requested during post-authentication resource authorization (AuthZ)
2430
+ * (e.g. ['https://www.googleapis.com/auth/drive.readonly'] or ['repo']).
2431
+ */
2432
+ resource?: string[];
2433
+ }
2434
+
2172
2435
  /**
2173
2436
  * Options for Scrypt password hashing.
2174
2437
  *
@@ -2237,12 +2500,26 @@ export declare class ScryptPasswordHasher implements IPasswordHasher {
2237
2500
  export declare class SelfManagedIdentityProvider implements IIdentityProvider {
2238
2501
  readonly name: string;
2239
2502
  private readonly manager;
2503
+ private readonly pendingSignups;
2504
+ private readonly requireVerification;
2505
+ private readonly config;
2240
2506
  constructor(configOrManager?: CredentialsConfig | CredentialsManager);
2241
2507
  private mapUser;
2508
+ private generateConfirmationCode;
2242
2509
  /**
2243
- * Registers a new user.
2510
+ * Registers a new user with optional pending verification.
2511
+ * When requireVerification is true, credentials are NOT persisted to the database until confirmSignUp() is called.
2244
2512
  */
2245
2513
  signUp(params: SignUpParams): Promise<UserIdentity>;
2514
+ /**
2515
+ * Confirms a pending signup registration using the verification code.
2516
+ * Only after successful confirmation is the user persisted to the database.
2517
+ */
2518
+ confirmSignUp(params: ConfirmSignUpParams): Promise<boolean>;
2519
+ /**
2520
+ * Resends the verification code for a pending signup.
2521
+ */
2522
+ resendConfirmationCode(params: ResendConfirmationCodeParams): Promise<ResendConfirmationCodeResult>;
2246
2523
  /**
2247
2524
  * Authenticates a user with password.
2248
2525
  */
@@ -2486,6 +2763,8 @@ export declare interface SessionStorage {
2486
2763
  * @public
2487
2764
  */
2488
2765
  export declare interface SignInParams {
2766
+ /** Target identity provider name when using CompositeIdentityProvider */
2767
+ provider?: string | undefined;
2489
2768
  /** Username or email of the account */
2490
2769
  username?: string | undefined;
2491
2770
  /** Primary identifier (username or email) */
@@ -2514,6 +2793,8 @@ export declare interface SignInResult<TSession = Session, TUser = UserIdentity>
2514
2793
  * @public
2515
2794
  */
2516
2795
  export declare interface SignUpParams {
2796
+ /** Target identity provider name when using CompositeIdentityProvider */
2797
+ provider?: string | undefined;
2517
2798
  /** Username for the user (can be used directly instead of identifier) */
2518
2799
  username?: string | undefined;
2519
2800
  /** Primary identifier (username or email) */
@@ -2538,6 +2819,20 @@ export declare interface SignUpResult<TSession = Session, TUser = UserIdentity>
2538
2819
  sessionId?: string | undefined;
2539
2820
  /** Created session object if autoCreateSessionOnSignUp is enabled */
2540
2821
  session?: TSession | undefined;
2822
+ requiresVerification?: boolean | undefined;
2823
+ devConfirmationCode?: string | undefined;
2824
+ }
2825
+
2826
+ /**
2827
+ * Thrown when attempting to sign up with username+password for an email that already has an SSO account.
2828
+ * The user should sign in via their original SSO provider and set a password in Settings.
2829
+ *
2830
+ * @public
2831
+ */
2832
+ export declare class SSOAccountAlreadyExistsError extends LixaError {
2833
+ readonly existingProviders: string[];
2834
+ readonly email: string;
2835
+ constructor(email: string, existingProviders: string[], details?: Record<string, unknown>);
2541
2836
  }
2542
2837
 
2543
2838
  /**
@@ -2738,7 +3033,7 @@ export declare interface StateStorage {
2738
3033
  * When provided to Lixa via config.storage, automatically configures session, state, and resource storage.
2739
3034
  * @public
2740
3035
  */
2741
- declare interface StorageAdapter {
3036
+ export declare interface StorageAdapter {
2742
3037
  sessionStorage?: any;
2743
3038
  resourceStorage?: any;
2744
3039
  stateStorage?: any;
@@ -2859,6 +3154,8 @@ export declare function validatePasswordPolicy(password: string, policy?: Passwo
2859
3154
  * @public
2860
3155
  */
2861
3156
  export declare interface VerifyCredentialsParams {
3157
+ /** Target identity provider name when using CompositeIdentityProvider */
3158
+ provider?: string | undefined;
2862
3159
  /** Username or email of the account */
2863
3160
  username?: string | undefined;
2864
3161
  /** Primary identifier (username or email) */