@nauth-toolkit/client 0.1.18 → 0.1.22

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.
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  NAuthModule: () => NAuthModule,
41
41
  authGuard: () => authGuard,
42
42
  authInterceptor: () => authInterceptor,
43
- oauthCallbackGuard: () => oauthCallbackGuard
43
+ socialRedirectCallbackGuard: () => socialRedirectCallbackGuard
44
44
  });
45
45
  module.exports = __toCommonJS(index_exports);
46
46
 
@@ -224,12 +224,12 @@ var defaultEndpoints = {
224
224
  mfaPreferred: "/mfa/preferred-method",
225
225
  mfaBackupCodes: "/mfa/backup-codes/generate",
226
226
  mfaExemption: "/mfa/exemption",
227
- socialAuthUrl: "/social/auth-url",
228
- socialCallback: "/social/callback",
229
227
  socialLinked: "/social/linked",
230
228
  socialLink: "/social/link",
231
229
  socialUnlink: "/social/unlink",
232
230
  socialVerify: "/social/:provider/verify",
231
+ socialRedirectStart: "/social/:provider/redirect",
232
+ socialExchange: "/social/exchange",
233
233
  trustDevice: "/trust-device",
234
234
  isTrustedDevice: "/is-trusted-device",
235
235
  auditHistory: "/audit/history",
@@ -381,6 +381,9 @@ var _BrowserStorage = class _BrowserStorage {
381
381
  async removeItem(key) {
382
382
  this.storage.removeItem(key);
383
383
  }
384
+ async clear() {
385
+ this.storage.clear();
386
+ }
384
387
  };
385
388
  __name(_BrowserStorage, "BrowserStorage");
386
389
  var BrowserStorage = _BrowserStorage;
@@ -399,6 +402,9 @@ var _InMemoryStorage = class _InMemoryStorage {
399
402
  async removeItem(key) {
400
403
  this.store.delete(key);
401
404
  }
405
+ async clear() {
406
+ this.store.clear();
407
+ }
402
408
  };
403
409
  __name(_InMemoryStorage, "InMemoryStorage");
404
410
  var InMemoryStorage = _InMemoryStorage;
@@ -523,9 +529,9 @@ var _FetchAdapter = class _FetchAdapter {
523
529
  });
524
530
  if (!response.ok) {
525
531
  const errorData = typeof data === "object" && data !== null ? data : {};
526
- const code = typeof errorData["code"] === "string" ? errorData.code : "INTERNAL_ERROR" /* INTERNAL_ERROR */;
527
- const message = typeof errorData["message"] === "string" ? errorData.message : `Request failed with status ${status}`;
528
- const timestamp = typeof errorData["timestamp"] === "string" ? errorData.timestamp : void 0;
532
+ const code = typeof errorData["code"] === "string" ? errorData["code"] : "INTERNAL_ERROR" /* INTERNAL_ERROR */;
533
+ const message = typeof errorData["message"] === "string" ? errorData["message"] : `Request failed with status ${status}`;
534
+ const timestamp = typeof errorData["timestamp"] === "string" ? errorData["timestamp"] : void 0;
529
535
  const details = errorData["details"];
530
536
  throw new NAuthClientError(code, message, {
531
537
  statusCode: status,
@@ -839,7 +845,9 @@ var _NAuthClient = class _NAuthClient {
839
845
  */
840
846
  async confirmForgotPassword(identifier, code, newPassword) {
841
847
  const payload = { identifier, code, newPassword };
842
- return this.post(this.config.endpoints.confirmForgotPassword, payload);
848
+ const result = await this.post(this.config.endpoints.confirmForgotPassword, payload);
849
+ await this.clearAuthState(false);
850
+ return result;
843
851
  }
844
852
  /**
845
853
  * Request password change (must change on next login).
@@ -949,126 +957,57 @@ var _NAuthClient = class _NAuthClient {
949
957
  // Social Authentication
950
958
  // ============================================================================
951
959
  /**
952
- * Start social OAuth flow with automatic state management.
960
+ * Start redirect-first social OAuth flow (web).
961
+ *
962
+ * This performs a browser navigation to:
963
+ * `GET {baseUrl}/social/:provider/redirect?returnTo=...&appState=...`
953
964
  *
954
- * Generates a secure state token, stores OAuth context, and redirects to the OAuth provider.
955
- * After OAuth callback, use `handleOAuthCallback()` to complete authentication.
965
+ * The backend:
966
+ * - generates and stores CSRF state (cluster-safe)
967
+ * - redirects the user to the provider
968
+ * - completes OAuth on callback and sets cookies (or issues an exchange token)
969
+ * - redirects back to `returnTo` with `appState` (and `exchangeToken` for json/hybrid)
956
970
  *
957
971
  * @param provider - OAuth provider ('google', 'apple', 'facebook')
958
- * @param options - Optional configuration
972
+ * @param options - Optional redirect options
959
973
  *
960
974
  * @example
961
975
  * ```typescript
962
- * // Simple usage
963
- * await client.loginWithSocial('google');
964
- *
965
- * // With custom redirect URI
966
- * await client.loginWithSocial('apple', {
967
- * redirectUri: 'https://example.com/auth/callback'
968
- * });
976
+ * await client.loginWithSocial('google', { returnTo: '/auth/callback', appState: '12345' });
969
977
  * ```
970
978
  */
971
- async loginWithSocial(provider, _options) {
979
+ async loginWithSocial(provider, options) {
972
980
  this.eventEmitter.emit({ type: "oauth:started", data: { provider }, timestamp: Date.now() });
973
- const { url } = await this.getSocialAuthUrl({ provider });
974
981
  if (hasWindow()) {
975
- window.location.href = url;
976
- }
977
- }
978
- /**
979
- * Auto-detect and handle OAuth callback.
980
- *
981
- * Call this on app initialization or in callback route.
982
- * Returns null if not an OAuth callback (no provider/code params).
983
- *
984
- * The SDK validates the state token, completes authentication via backend,
985
- * and emits appropriate events.
986
- *
987
- * @param urlOrParams - Optional URL string or URLSearchParams (auto-detects from window.location if not provided)
988
- * @returns AuthResponse if OAuth callback detected, null otherwise
989
- *
990
- * @example
991
- * ```typescript
992
- * // Auto-detect on app init
993
- * const response = await client.handleOAuthCallback();
994
- * if (response) {
995
- * if (response.challengeName) {
996
- * router.navigate(['/challenge', response.challengeName]);
997
- * } else {
998
- * router.navigate(['/']); // Navigate to your app's home route
999
- * }
1000
- * }
1001
- *
1002
- * // In callback route
1003
- * const response = await client.handleOAuthCallback(window.location.search);
1004
- * ```
1005
- */
1006
- async handleOAuthCallback(urlOrParams) {
1007
- let params;
1008
- if (urlOrParams instanceof URLSearchParams) {
1009
- params = urlOrParams;
1010
- } else if (typeof urlOrParams === "string") {
1011
- params = new URLSearchParams(urlOrParams);
1012
- } else if (hasWindow()) {
1013
- params = new URLSearchParams(window.location.search);
1014
- } else {
1015
- return null;
1016
- }
1017
- const provider = params.get("provider");
1018
- const code = params.get("code");
1019
- const state = params.get("state");
1020
- const error = params.get("error");
1021
- if (!provider || !code && !error) {
1022
- return null;
1023
- }
1024
- this.eventEmitter.emit({ type: "oauth:callback", data: { provider }, timestamp: Date.now() });
1025
- try {
1026
- if (error) {
1027
- const authError = new NAuthClientError(
1028
- "SOCIAL_TOKEN_INVALID" /* SOCIAL_TOKEN_INVALID */,
1029
- params.get("error_description") || error,
1030
- { details: { error, provider } }
1031
- );
1032
- this.eventEmitter.emit({ type: "oauth:error", data: authError, timestamp: Date.now() });
1033
- throw authError;
982
+ const startPath = this.config.endpoints.socialRedirectStart.replace(":provider", provider);
983
+ const base = this.config.baseUrl.replace(/\/$/, "");
984
+ const startUrl = new URL(`${base}${startPath}`);
985
+ const returnTo = options?.returnTo ?? this.config.redirects?.success ?? "/";
986
+ startUrl.searchParams.set("returnTo", returnTo);
987
+ if (options?.action === "link") {
988
+ startUrl.searchParams.set("action", "link");
1034
989
  }
1035
- if (!state) {
1036
- throw new NAuthClientError("CHALLENGE_INVALID" /* CHALLENGE_INVALID */, "Missing OAuth state parameter");
990
+ if (typeof options?.appState === "string" && options.appState.trim() !== "") {
991
+ startUrl.searchParams.set("appState", options.appState);
1037
992
  }
1038
- const response = await this.handleSocialCallback({
1039
- provider,
1040
- code,
1041
- state
1042
- });
1043
- if (response.challengeName) {
1044
- this.eventEmitter.emit({ type: "auth:challenge", data: response, timestamp: Date.now() });
1045
- } else {
1046
- this.eventEmitter.emit({ type: "auth:success", data: response, timestamp: Date.now() });
1047
- }
1048
- this.eventEmitter.emit({ type: "oauth:completed", data: response, timestamp: Date.now() });
1049
- return response;
1050
- } catch (error2) {
1051
- const authError = error2 instanceof NAuthClientError ? error2 : new NAuthClientError(
1052
- "SOCIAL_TOKEN_INVALID" /* SOCIAL_TOKEN_INVALID */,
1053
- error2.message || "OAuth callback failed"
1054
- );
1055
- this.eventEmitter.emit({ type: "oauth:error", data: authError, timestamp: Date.now() });
1056
- throw authError;
993
+ window.location.href = startUrl.toString();
1057
994
  }
1058
995
  }
1059
996
  /**
1060
- * Get social auth URL (low-level API).
997
+ * Exchange an `exchangeToken` (from redirect callback URL) into an AuthResponse.
1061
998
  *
1062
- * For most cases, use `loginWithSocial()` which handles state management automatically.
1063
- */
1064
- async getSocialAuthUrl(request) {
1065
- return this.post(this.config.endpoints.socialAuthUrl, request);
1066
- }
1067
- /**
1068
- * Handle social callback.
999
+ * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back
1000
+ * with `exchangeToken` instead of setting cookies.
1001
+ *
1002
+ * @param exchangeToken - One-time exchange token from the callback URL
1003
+ * @returns AuthResponse
1069
1004
  */
1070
- async handleSocialCallback(request) {
1071
- const result = await this.post(this.config.endpoints.socialCallback, request);
1005
+ async exchangeSocialRedirect(exchangeToken) {
1006
+ const token = exchangeToken?.trim();
1007
+ if (!token) {
1008
+ throw new NAuthClientError("CHALLENGE_INVALID" /* CHALLENGE_INVALID */, "Missing exchangeToken");
1009
+ }
1010
+ const result = await this.post(this.config.endpoints.socialExchange, { exchangeToken: token });
1072
1011
  await this.handleAuthResponse(result);
1073
1012
  return result;
1074
1013
  }
@@ -1257,7 +1196,9 @@ var _NAuthClient = class _NAuthClient {
1257
1196
  await this.setDeviceToken(response.deviceToken);
1258
1197
  }
1259
1198
  if (response.user) {
1260
- await this.setUser(response.user);
1199
+ const user = response.user;
1200
+ user.sessionAuthMethod = response.authMethod ?? null;
1201
+ await this.setUser(user);
1261
1202
  }
1262
1203
  await this.clearChallenge();
1263
1204
  }
@@ -1329,6 +1270,15 @@ var _NAuthClient = class _NAuthClient {
1329
1270
  headers["Authorization"] = `Bearer ${accessToken}`;
1330
1271
  }
1331
1272
  }
1273
+ if (this.config.tokenDelivery === "json") {
1274
+ try {
1275
+ const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);
1276
+ if (deviceToken) {
1277
+ headers[this.config.deviceTrust.headerName] = deviceToken;
1278
+ }
1279
+ } catch {
1280
+ }
1281
+ }
1332
1282
  if (this.config.tokenDelivery === "cookies" && hasWindow()) {
1333
1283
  const csrfToken = this.getCsrfToken();
1334
1284
  if (csrfToken) {
@@ -1577,6 +1527,22 @@ var AuthService = class {
1577
1527
  refresh() {
1578
1528
  return (0, import_rxjs2.from)(this.client.refreshTokens());
1579
1529
  }
1530
+ /**
1531
+ * Refresh tokens (promise-based).
1532
+ *
1533
+ * Returns a promise instead of an Observable, matching the core NAuthClient API.
1534
+ * Useful for async/await patterns in guards and interceptors.
1535
+ *
1536
+ * @returns Promise of TokenResponse
1537
+ *
1538
+ * @example
1539
+ * ```typescript
1540
+ * const tokens = await auth.refreshTokensPromise();
1541
+ * ```
1542
+ */
1543
+ refreshTokensPromise() {
1544
+ return this.client.refreshTokens();
1545
+ }
1580
1546
  // ============================================================================
1581
1547
  // Account Recovery (Forgot Password)
1582
1548
  // ============================================================================
@@ -1592,6 +1558,95 @@ var AuthService = class {
1592
1558
  confirmForgotPassword(identifier, code, newPassword) {
1593
1559
  return (0, import_rxjs2.from)(this.client.confirmForgotPassword(identifier, code, newPassword));
1594
1560
  }
1561
+ /**
1562
+ * Change user password (requires current password).
1563
+ *
1564
+ * @param oldPassword - Current password
1565
+ * @param newPassword - New password (must meet requirements)
1566
+ * @returns Observable that completes when password is changed
1567
+ *
1568
+ * @example
1569
+ * ```typescript
1570
+ * this.auth.changePassword('oldPassword123', 'newSecurePassword456!').subscribe({
1571
+ * next: () => console.log('Password changed successfully'),
1572
+ * error: (err) => console.error('Failed to change password:', err)
1573
+ * });
1574
+ * ```
1575
+ */
1576
+ changePassword(oldPassword, newPassword) {
1577
+ return (0, import_rxjs2.from)(this.client.changePassword(oldPassword, newPassword));
1578
+ }
1579
+ /**
1580
+ * Request password change (must change on next login).
1581
+ *
1582
+ * @returns Observable that completes when request is sent
1583
+ */
1584
+ requestPasswordChange() {
1585
+ return (0, import_rxjs2.from)(this.client.requestPasswordChange());
1586
+ }
1587
+ // ============================================================================
1588
+ // Profile Management
1589
+ // ============================================================================
1590
+ /**
1591
+ * Get current user profile.
1592
+ *
1593
+ * @returns Observable of current user profile
1594
+ *
1595
+ * @example
1596
+ * ```typescript
1597
+ * this.auth.getProfile().subscribe(user => {
1598
+ * console.log('User profile:', user);
1599
+ * });
1600
+ * ```
1601
+ */
1602
+ getProfile() {
1603
+ return (0, import_rxjs2.from)(
1604
+ this.client.getProfile().then((user) => {
1605
+ this.currentUserSubject.next(user);
1606
+ return user;
1607
+ })
1608
+ );
1609
+ }
1610
+ /**
1611
+ * Get current user profile (promise-based).
1612
+ *
1613
+ * Returns a promise instead of an Observable, matching the core NAuthClient API.
1614
+ * Useful for async/await patterns in guards and interceptors.
1615
+ *
1616
+ * @returns Promise of current user profile
1617
+ *
1618
+ * @example
1619
+ * ```typescript
1620
+ * const user = await auth.getProfilePromise();
1621
+ * ```
1622
+ */
1623
+ getProfilePromise() {
1624
+ return this.client.getProfile().then((user) => {
1625
+ this.currentUserSubject.next(user);
1626
+ return user;
1627
+ });
1628
+ }
1629
+ /**
1630
+ * Update user profile.
1631
+ *
1632
+ * @param updates - Profile fields to update
1633
+ * @returns Observable of updated user profile
1634
+ *
1635
+ * @example
1636
+ * ```typescript
1637
+ * this.auth.updateProfile({ firstName: 'John', lastName: 'Doe' }).subscribe(user => {
1638
+ * console.log('Profile updated:', user);
1639
+ * });
1640
+ * ```
1641
+ */
1642
+ updateProfile(updates) {
1643
+ return (0, import_rxjs2.from)(
1644
+ this.client.updateProfile(updates).then((user) => {
1645
+ this.currentUserSubject.next(user);
1646
+ return user;
1647
+ })
1648
+ );
1649
+ }
1595
1650
  // ============================================================================
1596
1651
  // Challenge Flow Methods (Essential for any auth flow)
1597
1652
  // ============================================================================
@@ -1648,26 +1703,189 @@ var AuthService = class {
1648
1703
  // ============================================================================
1649
1704
  /**
1650
1705
  * Initiate social OAuth login flow.
1651
- * Redirects to OAuth provider with automatic state management.
1706
+ * Redirects the browser to backend `/auth/social/:provider/redirect`.
1652
1707
  */
1653
1708
  loginWithSocial(provider, options) {
1654
1709
  return this.client.loginWithSocial(provider, options);
1655
1710
  }
1656
1711
  /**
1657
- * Get social auth URL to redirect user for OAuth (low-level API).
1712
+ * Exchange an exchangeToken (from redirect callback URL) into an AuthResponse.
1713
+ *
1714
+ * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back
1715
+ * with `exchangeToken` instead of setting cookies.
1716
+ *
1717
+ * @param exchangeToken - One-time exchange token from the callback URL
1718
+ * @returns Observable of AuthResponse
1658
1719
  */
1659
- getSocialAuthUrl(provider, redirectUri) {
1660
- return (0, import_rxjs2.from)(
1661
- this.client.getSocialAuthUrl({ provider, redirectUri })
1662
- );
1720
+ exchangeSocialRedirect(exchangeToken) {
1721
+ return (0, import_rxjs2.from)(this.client.exchangeSocialRedirect(exchangeToken).then((res) => this.updateChallengeState(res)));
1663
1722
  }
1664
1723
  /**
1665
- * Handle social auth callback (low-level API).
1724
+ * Exchange an exchangeToken (from redirect callback URL) into an AuthResponse (promise-based).
1725
+ *
1726
+ * Returns a promise instead of an Observable, matching the core NAuthClient API.
1727
+ * Useful for async/await patterns in guards and interceptors.
1728
+ *
1729
+ * @param exchangeToken - One-time exchange token from the callback URL
1730
+ * @returns Promise of AuthResponse
1731
+ *
1732
+ * @example
1733
+ * ```typescript
1734
+ * const response = await auth.exchangeSocialRedirectPromise(exchangeToken);
1735
+ * ```
1666
1736
  */
1667
- handleSocialCallback(provider, code, state) {
1668
- return (0, import_rxjs2.from)(
1669
- this.client.handleSocialCallback({ provider, code, state }).then((res) => this.updateChallengeState(res))
1670
- );
1737
+ exchangeSocialRedirectPromise(exchangeToken) {
1738
+ return this.client.exchangeSocialRedirect(exchangeToken).then((res) => this.updateChallengeState(res));
1739
+ }
1740
+ /**
1741
+ * Verify native social token (mobile).
1742
+ *
1743
+ * @param request - Social verification request with provider and token
1744
+ * @returns Observable of AuthResponse
1745
+ */
1746
+ verifyNativeSocial(request) {
1747
+ return (0, import_rxjs2.from)(this.client.verifyNativeSocial(request).then((res) => this.updateChallengeState(res)));
1748
+ }
1749
+ /**
1750
+ * Get linked social accounts.
1751
+ *
1752
+ * @returns Observable of linked accounts response
1753
+ */
1754
+ getLinkedAccounts() {
1755
+ return (0, import_rxjs2.from)(this.client.getLinkedAccounts());
1756
+ }
1757
+ /**
1758
+ * Link social account.
1759
+ *
1760
+ * @param provider - Social provider to link
1761
+ * @param code - OAuth authorization code
1762
+ * @param state - OAuth state parameter
1763
+ * @returns Observable with success message
1764
+ */
1765
+ linkSocialAccount(provider, code, state) {
1766
+ return (0, import_rxjs2.from)(this.client.linkSocialAccount(provider, code, state));
1767
+ }
1768
+ /**
1769
+ * Unlink social account.
1770
+ *
1771
+ * @param provider - Social provider to unlink
1772
+ * @returns Observable with success message
1773
+ */
1774
+ unlinkSocialAccount(provider) {
1775
+ return (0, import_rxjs2.from)(this.client.unlinkSocialAccount(provider));
1776
+ }
1777
+ // ============================================================================
1778
+ // MFA Management
1779
+ // ============================================================================
1780
+ /**
1781
+ * Get MFA status for the current user.
1782
+ *
1783
+ * @returns Observable of MFA status
1784
+ */
1785
+ getMfaStatus() {
1786
+ return (0, import_rxjs2.from)(this.client.getMfaStatus());
1787
+ }
1788
+ /**
1789
+ * Get MFA devices for the current user.
1790
+ *
1791
+ * @returns Observable of MFA devices array
1792
+ */
1793
+ getMfaDevices() {
1794
+ return (0, import_rxjs2.from)(this.client.getMfaDevices());
1795
+ }
1796
+ /**
1797
+ * Setup MFA device (authenticated user).
1798
+ *
1799
+ * @param method - MFA method to set up
1800
+ * @returns Observable of setup data
1801
+ */
1802
+ setupMfaDevice(method) {
1803
+ return (0, import_rxjs2.from)(this.client.setupMfaDevice(method));
1804
+ }
1805
+ /**
1806
+ * Verify MFA setup (authenticated user).
1807
+ *
1808
+ * @param method - MFA method
1809
+ * @param setupData - Setup data from setupMfaDevice
1810
+ * @param deviceName - Optional device name
1811
+ * @returns Observable with device ID
1812
+ */
1813
+ verifyMfaSetup(method, setupData, deviceName) {
1814
+ return (0, import_rxjs2.from)(this.client.verifyMfaSetup(method, setupData, deviceName));
1815
+ }
1816
+ /**
1817
+ * Remove MFA device.
1818
+ *
1819
+ * @param method - MFA method to remove
1820
+ * @returns Observable with success message
1821
+ */
1822
+ removeMfaDevice(method) {
1823
+ return (0, import_rxjs2.from)(this.client.removeMfaDevice(method));
1824
+ }
1825
+ /**
1826
+ * Set preferred MFA method.
1827
+ *
1828
+ * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey')
1829
+ * @returns Observable with success message
1830
+ */
1831
+ setPreferredMfaMethod(method) {
1832
+ return (0, import_rxjs2.from)(this.client.setPreferredMfaMethod(method));
1833
+ }
1834
+ /**
1835
+ * Generate backup codes.
1836
+ *
1837
+ * @returns Observable of backup codes array
1838
+ */
1839
+ generateBackupCodes() {
1840
+ return (0, import_rxjs2.from)(this.client.generateBackupCodes());
1841
+ }
1842
+ /**
1843
+ * Set MFA exemption (admin/test scenarios).
1844
+ *
1845
+ * @param exempt - Whether to exempt user from MFA
1846
+ * @param reason - Optional reason for exemption
1847
+ * @returns Observable that completes when exemption is set
1848
+ */
1849
+ setMfaExemption(exempt, reason) {
1850
+ return (0, import_rxjs2.from)(this.client.setMfaExemption(exempt, reason));
1851
+ }
1852
+ // ============================================================================
1853
+ // Device Trust
1854
+ // ============================================================================
1855
+ /**
1856
+ * Trust current device.
1857
+ *
1858
+ * @returns Observable with device token
1859
+ */
1860
+ trustDevice() {
1861
+ return (0, import_rxjs2.from)(this.client.trustDevice());
1862
+ }
1863
+ /**
1864
+ * Check if the current device is trusted.
1865
+ *
1866
+ * @returns Observable with trusted status
1867
+ */
1868
+ isTrustedDevice() {
1869
+ return (0, import_rxjs2.from)(this.client.isTrustedDevice());
1870
+ }
1871
+ // ============================================================================
1872
+ // Audit History
1873
+ // ============================================================================
1874
+ /**
1875
+ * Get paginated audit history for the current user.
1876
+ *
1877
+ * @param params - Query parameters for filtering and pagination
1878
+ * @returns Observable of audit history response
1879
+ *
1880
+ * @example
1881
+ * ```typescript
1882
+ * this.auth.getAuditHistory({ page: 1, limit: 20, eventType: 'LOGIN_SUCCESS' }).subscribe(history => {
1883
+ * console.log('Audit history:', history);
1884
+ * });
1885
+ * ```
1886
+ */
1887
+ getAuditHistory(params) {
1888
+ return (0, import_rxjs2.from)(this.client.getAuditHistory(params));
1671
1889
  }
1672
1890
  // ============================================================================
1673
1891
  // Escape Hatch
@@ -1675,20 +1893,19 @@ var AuthService = class {
1675
1893
  /**
1676
1894
  * Expose underlying NAuthClient for advanced scenarios.
1677
1895
  *
1678
- * Use this for operations not directly exposed by this service:
1679
- * - Profile management (getProfile, updateProfile)
1680
- * - MFA management (getMfaStatus, setupMfaDevice, etc.)
1681
- * - Social account linking (linkSocialAccount, unlinkSocialAccount)
1682
- * - Audit history (getAuditHistory)
1683
- * - Device trust (trustDevice)
1896
+ * @deprecated All core functionality is now exposed directly on AuthService as Observables.
1897
+ * Use the direct methods on AuthService instead (e.g., `auth.changePassword()` instead of `auth.getClient().changePassword()`).
1898
+ * This method is kept for backward compatibility only and may be removed in a future version.
1899
+ *
1900
+ * @returns The underlying NAuthClient instance
1684
1901
  *
1685
1902
  * @example
1686
1903
  * ```typescript
1687
- * // Get MFA status
1904
+ * // Deprecated - use direct methods instead
1688
1905
  * const status = await this.auth.getClient().getMfaStatus();
1689
1906
  *
1690
- * // Update profile
1691
- * const user = await this.auth.getClient().updateProfile({ firstName: 'John' });
1907
+ * // Preferred - use Observable-based methods
1908
+ * this.auth.getMfaStatus().subscribe(status => ...);
1692
1909
  * ```
1693
1910
  */
1694
1911
  getClient() {
@@ -1767,12 +1984,11 @@ var authInterceptor = /* @__PURE__ */ __name((req, next) => {
1767
1984
  const refreshPath = endpoints.refresh ?? "/refresh";
1768
1985
  const loginPath = endpoints.login ?? "/login";
1769
1986
  const signupPath = endpoints.signup ?? "/signup";
1770
- const socialAuthUrlPath = endpoints.socialAuthUrl ?? "/social/auth-url";
1771
- const socialCallbackPath = endpoints.socialCallback ?? "/social/callback";
1987
+ const socialExchangePath = endpoints.socialExchange ?? "/social/exchange";
1772
1988
  const refreshUrl = `${baseUrl}${refreshPath}`;
1773
1989
  const isAuthApiRequest = req.url.includes(baseUrl);
1774
1990
  const isRefreshEndpoint = req.url.includes(refreshPath);
1775
- const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialAuthUrlPath) || req.url.includes(socialCallbackPath);
1991
+ const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
1776
1992
  let authReq = req;
1777
1993
  if (tokenDelivery === "cookies") {
1778
1994
  authReq = authReq.clone({ withCredentials: true });
@@ -1800,7 +2016,7 @@ var authInterceptor = /* @__PURE__ */ __name((req, next) => {
1800
2016
  if (config.debug) {
1801
2017
  console.warn("[nauth-interceptor] Starting refresh...");
1802
2018
  }
1803
- const refresh$ = tokenDelivery === "cookies" ? http.post(refreshUrl, {}, { withCredentials: true }) : (0, import_rxjs3.from)(authService.getClient().refreshTokens());
2019
+ const refresh$ = tokenDelivery === "cookies" ? http.post(refreshUrl, {}, { withCredentials: true }) : (0, import_rxjs3.from)(authService.refreshTokensPromise());
1804
2020
  return refresh$.pipe(
1805
2021
  (0, import_rxjs3.switchMap)((response) => {
1806
2022
  if (config.debug) {
@@ -1907,10 +2123,10 @@ var _AuthGuard = class _AuthGuard {
1907
2123
  __name(_AuthGuard, "AuthGuard");
1908
2124
  var AuthGuard = _AuthGuard;
1909
2125
 
1910
- // src/angular/oauth-callback.guard.ts
2126
+ // src/angular/social-redirect-callback.guard.ts
1911
2127
  var import_core6 = require("@angular/core");
1912
2128
  var import_common2 = require("@angular/common");
1913
- var oauthCallbackGuard = /* @__PURE__ */ __name(async () => {
2129
+ var socialRedirectCallbackGuard = /* @__PURE__ */ __name(async () => {
1914
2130
  const auth = (0, import_core6.inject)(AuthService);
1915
2131
  const config = (0, import_core6.inject)(NAUTH_CLIENT_CONFIG);
1916
2132
  const platformId = (0, import_core6.inject)(import_core6.PLATFORM_ID);
@@ -1918,38 +2134,37 @@ var oauthCallbackGuard = /* @__PURE__ */ __name(async () => {
1918
2134
  if (!isBrowser) {
1919
2135
  return false;
1920
2136
  }
1921
- try {
1922
- const response = await auth.getClient().handleOAuthCallback();
1923
- if (!response) {
1924
- const homeUrl = config.redirects?.success || "/";
1925
- window.location.replace(homeUrl);
1926
- return false;
1927
- }
1928
- if (response.challengeName) {
1929
- const challengeBase = config.redirects?.challengeBase || "/auth/challenge";
1930
- const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, "-");
1931
- const challengePath = `${challengeBase}/${challengeRoute}`;
1932
- if (config.debug) {
1933
- console.warn("[oauth-callback-guard] Redirecting to challenge:", challengePath);
1934
- }
1935
- window.location.replace(challengePath);
1936
- } else {
1937
- const successUrl = config.redirects?.success || "/";
1938
- if (config.debug) {
1939
- console.warn("[oauth-callback-guard] Redirecting to success URL:", successUrl);
1940
- }
1941
- window.location.replace(successUrl);
1942
- }
1943
- } catch (error) {
1944
- console.error("[oauth-callback-guard] OAuth callback failed:", error);
2137
+ const params = new URLSearchParams(window.location.search);
2138
+ const error = params.get("error");
2139
+ const exchangeToken = params.get("exchangeToken");
2140
+ if (error) {
1945
2141
  const errorUrl = config.redirects?.oauthError || "/login";
1946
- if (config.debug) {
1947
- console.warn("[oauth-callback-guard] Redirecting to error URL:", errorUrl);
1948
- }
1949
2142
  window.location.replace(errorUrl);
2143
+ return false;
2144
+ }
2145
+ if (!exchangeToken) {
2146
+ try {
2147
+ await auth.getProfilePromise();
2148
+ } catch {
2149
+ const errorUrl = config.redirects?.oauthError || "/login";
2150
+ window.location.replace(errorUrl);
2151
+ return false;
2152
+ }
2153
+ const successUrl2 = config.redirects?.success || "/";
2154
+ window.location.replace(successUrl2);
2155
+ return false;
2156
+ }
2157
+ const response = await auth.exchangeSocialRedirectPromise(exchangeToken);
2158
+ if (response.challengeName) {
2159
+ const challengeBase = config.redirects?.challengeBase || "/auth/challenge";
2160
+ const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, "-");
2161
+ window.location.replace(`${challengeBase}/${challengeRoute}`);
2162
+ return false;
1950
2163
  }
2164
+ const successUrl = config.redirects?.success || "/";
2165
+ window.location.replace(successUrl);
1951
2166
  return false;
1952
- }, "oauthCallbackGuard");
2167
+ }, "socialRedirectCallbackGuard");
1953
2168
 
1954
2169
  // src/angular/auth.module.ts
1955
2170
  var import_core7 = require("@angular/core");
@@ -1984,6 +2199,6 @@ NAuthModule = __decorateClass([
1984
2199
  NAuthModule,
1985
2200
  authGuard,
1986
2201
  authInterceptor,
1987
- oauthCallbackGuard
2202
+ socialRedirectCallbackGuard
1988
2203
  });
1989
2204
  //# sourceMappingURL=index.cjs.map