@oxyhq/core 3.4.1 → 3.4.2

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 (174) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/AuthManager.js +91 -319
  3. package/dist/cjs/CrossDomainAuth.js +19 -106
  4. package/dist/cjs/HttpService.js +49 -73
  5. package/dist/cjs/OxyServices.base.js +2 -2
  6. package/dist/cjs/i18n/index.js +7 -1
  7. package/dist/cjs/i18n/locales/ar-SA.json +18 -2
  8. package/dist/cjs/i18n/locales/ca-ES.json +18 -2
  9. package/dist/cjs/i18n/locales/de-DE.json +18 -2
  10. package/dist/cjs/i18n/locales/en-US.json +16 -2
  11. package/dist/cjs/i18n/locales/es-ES.json +16 -2
  12. package/dist/cjs/i18n/locales/fr-FR.json +18 -2
  13. package/dist/cjs/i18n/locales/it-IT.json +18 -2
  14. package/dist/cjs/i18n/locales/ja-JP.json +18 -2
  15. package/dist/cjs/i18n/locales/ko-KR.json +18 -2
  16. package/dist/cjs/i18n/locales/locales/ar-SA.json +18 -2
  17. package/dist/cjs/i18n/locales/locales/ca-ES.json +18 -2
  18. package/dist/cjs/i18n/locales/locales/de-DE.json +18 -2
  19. package/dist/cjs/i18n/locales/locales/en-US.json +17 -3
  20. package/dist/cjs/i18n/locales/locales/es-ES.json +16 -2
  21. package/dist/cjs/i18n/locales/locales/fr-FR.json +18 -2
  22. package/dist/cjs/i18n/locales/locales/it-IT.json +18 -2
  23. package/dist/cjs/i18n/locales/locales/ja-JP.json +18 -2
  24. package/dist/cjs/i18n/locales/locales/ko-KR.json +18 -2
  25. package/dist/cjs/i18n/locales/locales/pt-PT.json +18 -2
  26. package/dist/cjs/i18n/locales/locales/zh-CN.json +18 -2
  27. package/dist/cjs/i18n/locales/pt-PT.json +18 -2
  28. package/dist/cjs/i18n/locales/zh-CN.json +18 -2
  29. package/dist/cjs/mixins/OxyServices.auth.js +20 -63
  30. package/dist/cjs/mixins/OxyServices.fedcm.js +10 -12
  31. package/dist/cjs/mixins/OxyServices.popup.js +50 -299
  32. package/dist/cjs/mixins/OxyServices.redirect.js +84 -348
  33. package/dist/cjs/mixins/OxyServices.silent.js +204 -0
  34. package/dist/cjs/mixins/OxyServices.sso.js +4 -5
  35. package/dist/cjs/mixins/OxyServices.utility.js +6 -15
  36. package/dist/cjs/mixins/index.js +5 -6
  37. package/dist/cjs/server/index.js +21 -0
  38. package/dist/cjs/server/rateLimit.js +77 -0
  39. package/dist/cjs/shared/utils/debugUtils.js +1 -1
  40. package/dist/cjs/utils/accountUtils.js +4 -4
  41. package/dist/cjs/utils/authHelpers.js +21 -15
  42. package/dist/cjs/utils/coldBoot.js +3 -3
  43. package/dist/cjs/utils/fapiAutoDetect.js +1 -1
  44. package/dist/esm/.tsbuildinfo +1 -1
  45. package/dist/esm/AuthManager.js +91 -319
  46. package/dist/esm/CrossDomainAuth.js +19 -106
  47. package/dist/esm/HttpService.js +49 -73
  48. package/dist/esm/OxyServices.base.js +2 -2
  49. package/dist/esm/i18n/index.js +7 -1
  50. package/dist/esm/i18n/locales/ar-SA.json +18 -2
  51. package/dist/esm/i18n/locales/ca-ES.json +18 -2
  52. package/dist/esm/i18n/locales/de-DE.json +18 -2
  53. package/dist/esm/i18n/locales/en-US.json +16 -2
  54. package/dist/esm/i18n/locales/es-ES.json +16 -2
  55. package/dist/esm/i18n/locales/fr-FR.json +18 -2
  56. package/dist/esm/i18n/locales/it-IT.json +18 -2
  57. package/dist/esm/i18n/locales/ja-JP.json +18 -2
  58. package/dist/esm/i18n/locales/ko-KR.json +18 -2
  59. package/dist/esm/i18n/locales/locales/ar-SA.json +18 -2
  60. package/dist/esm/i18n/locales/locales/ca-ES.json +18 -2
  61. package/dist/esm/i18n/locales/locales/de-DE.json +18 -2
  62. package/dist/esm/i18n/locales/locales/en-US.json +17 -3
  63. package/dist/esm/i18n/locales/locales/es-ES.json +16 -2
  64. package/dist/esm/i18n/locales/locales/fr-FR.json +18 -2
  65. package/dist/esm/i18n/locales/locales/it-IT.json +18 -2
  66. package/dist/esm/i18n/locales/locales/ja-JP.json +18 -2
  67. package/dist/esm/i18n/locales/locales/ko-KR.json +18 -2
  68. package/dist/esm/i18n/locales/locales/pt-PT.json +18 -2
  69. package/dist/esm/i18n/locales/locales/zh-CN.json +18 -2
  70. package/dist/esm/i18n/locales/pt-PT.json +18 -2
  71. package/dist/esm/i18n/locales/zh-CN.json +18 -2
  72. package/dist/esm/mixins/OxyServices.auth.js +20 -63
  73. package/dist/esm/mixins/OxyServices.fedcm.js +10 -12
  74. package/dist/esm/mixins/OxyServices.popup.js +52 -301
  75. package/dist/esm/mixins/OxyServices.redirect.js +84 -349
  76. package/dist/esm/mixins/OxyServices.silent.js +202 -0
  77. package/dist/esm/mixins/OxyServices.sso.js +4 -5
  78. package/dist/esm/mixins/OxyServices.utility.js +6 -15
  79. package/dist/esm/mixins/index.js +5 -6
  80. package/dist/esm/server/index.js +17 -0
  81. package/dist/esm/server/rateLimit.js +71 -0
  82. package/dist/esm/shared/utils/debugUtils.js +1 -1
  83. package/dist/esm/utils/accountUtils.js +4 -4
  84. package/dist/esm/utils/authHelpers.js +21 -15
  85. package/dist/esm/utils/coldBoot.js +3 -3
  86. package/dist/esm/utils/fapiAutoDetect.js +1 -1
  87. package/dist/types/.tsbuildinfo +1 -1
  88. package/dist/types/AuthManager.d.ts +26 -53
  89. package/dist/types/AuthManagerTypes.d.ts +5 -9
  90. package/dist/types/CrossDomainAuth.d.ts +13 -52
  91. package/dist/types/HttpService.d.ts +9 -8
  92. package/dist/types/OxyServices.base.d.ts +1 -1
  93. package/dist/types/OxyServices.d.ts +4 -10
  94. package/dist/types/index.d.ts +1 -1
  95. package/dist/types/mixins/OxyServices.analytics.d.ts +1 -1
  96. package/dist/types/mixins/OxyServices.appData.d.ts +1 -1
  97. package/dist/types/mixins/OxyServices.applications.d.ts +1 -1
  98. package/dist/types/mixins/OxyServices.assets.d.ts +1 -1
  99. package/dist/types/mixins/OxyServices.auth.d.ts +10 -31
  100. package/dist/types/mixins/OxyServices.contacts.d.ts +1 -1
  101. package/dist/types/mixins/OxyServices.devices.d.ts +1 -1
  102. package/dist/types/mixins/OxyServices.features.d.ts +1 -1
  103. package/dist/types/mixins/OxyServices.fedcm.d.ts +5 -5
  104. package/dist/types/mixins/OxyServices.language.d.ts +1 -1
  105. package/dist/types/mixins/OxyServices.location.d.ts +1 -1
  106. package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -1
  107. package/dist/types/mixins/OxyServices.payment.d.ts +1 -1
  108. package/dist/types/mixins/OxyServices.popup.d.ts +18 -120
  109. package/dist/types/mixins/OxyServices.privacy.d.ts +1 -1
  110. package/dist/types/mixins/OxyServices.redirect.d.ts +13 -174
  111. package/dist/types/mixins/OxyServices.reputation.d.ts +1 -1
  112. package/dist/types/mixins/OxyServices.security.d.ts +1 -1
  113. package/dist/types/mixins/OxyServices.silent.d.ts +131 -0
  114. package/dist/types/mixins/OxyServices.sso.d.ts +4 -5
  115. package/dist/types/mixins/OxyServices.topics.d.ts +1 -1
  116. package/dist/types/mixins/OxyServices.user.d.ts +1 -1
  117. package/dist/types/mixins/OxyServices.utility.d.ts +3 -8
  118. package/dist/types/mixins/OxyServices.workspaces.d.ts +1 -1
  119. package/dist/types/mixins/index.d.ts +3 -3
  120. package/dist/types/models/interfaces.d.ts +5 -16
  121. package/dist/types/models/session.d.ts +0 -2
  122. package/dist/types/server/index.d.ts +18 -0
  123. package/dist/types/server/rateLimit.d.ts +40 -0
  124. package/dist/types/shared/utils/debugUtils.d.ts +1 -1
  125. package/dist/types/utils/authHelpers.d.ts +4 -3
  126. package/dist/types/utils/coldBoot.d.ts +2 -2
  127. package/dist/types/utils/fapiAutoDetect.d.ts +1 -1
  128. package/package.json +24 -2
  129. package/src/AuthManager.ts +100 -370
  130. package/src/AuthManagerTypes.ts +5 -9
  131. package/src/CrossDomainAuth.ts +22 -129
  132. package/src/HttpService.ts +55 -73
  133. package/src/OxyServices.base.ts +2 -3
  134. package/src/OxyServices.ts +9 -11
  135. package/src/__tests__/authManager.cookiePath.test.ts +19 -17
  136. package/src/__tests__/authManager.security.test.ts +7 -3
  137. package/src/__tests__/crossDomainAuth.test.ts +26 -118
  138. package/src/i18n/index.ts +7 -1
  139. package/src/i18n/locales/ar-SA.json +18 -2
  140. package/src/i18n/locales/ca-ES.json +18 -2
  141. package/src/i18n/locales/de-DE.json +18 -2
  142. package/src/i18n/locales/en-US.json +17 -3
  143. package/src/i18n/locales/es-ES.json +16 -2
  144. package/src/i18n/locales/fr-FR.json +18 -2
  145. package/src/i18n/locales/it-IT.json +18 -2
  146. package/src/i18n/locales/ja-JP.json +18 -2
  147. package/src/i18n/locales/ko-KR.json +18 -2
  148. package/src/i18n/locales/pt-PT.json +18 -2
  149. package/src/i18n/locales/zh-CN.json +18 -2
  150. package/src/index.ts +1 -1
  151. package/src/mixins/OxyServices.auth.ts +23 -75
  152. package/src/mixins/OxyServices.fedcm.ts +10 -12
  153. package/src/mixins/OxyServices.redirect.ts +82 -371
  154. package/src/mixins/OxyServices.silent.ts +272 -0
  155. package/src/mixins/OxyServices.sso.ts +5 -6
  156. package/src/mixins/OxyServices.utility.ts +9 -22
  157. package/src/mixins/__tests__/appData.test.ts +1 -1
  158. package/src/mixins/__tests__/onTokensChanged.test.ts +1 -1
  159. package/src/mixins/__tests__/reputation.test.ts +1 -1
  160. package/src/mixins/__tests__/serviceAuth.test.ts +7 -5
  161. package/src/mixins/__tests__/silent.test.ts +102 -0
  162. package/src/mixins/__tests__/verifyChallenge.test.ts +9 -14
  163. package/src/mixins/index.ts +6 -8
  164. package/src/models/interfaces.ts +5 -16
  165. package/src/models/session.ts +1 -3
  166. package/src/server/index.ts +19 -0
  167. package/src/server/rateLimit.ts +170 -0
  168. package/src/shared/utils/debugUtils.ts +1 -1
  169. package/src/utils/accountUtils.ts +4 -4
  170. package/src/utils/authHelpers.ts +23 -15
  171. package/src/utils/coldBoot.ts +4 -4
  172. package/src/utils/fapiAutoDetect.ts +1 -1
  173. package/src/mixins/OxyServices.popup.ts +0 -631
  174. package/src/mixins/__tests__/popup.test.ts +0 -374
@@ -24,7 +24,7 @@ export type AuthStateChangeCallback = (user: MinimalUserData | null) => void;
24
24
  /**
25
25
  * Auth method types.
26
26
  */
27
- export type AuthMethod = 'fedcm' | 'popup' | 'redirect' | 'credentials' | 'identity';
27
+ export type AuthMethod = 'fedcm' | 'redirect' | 'credentials' | 'identity';
28
28
  /**
29
29
  * Auth manager configuration.
30
30
  */
@@ -37,20 +37,6 @@ export interface AuthManagerConfig {
37
37
  refreshBuffer?: number;
38
38
  /** Enable cross-tab coordination via BroadcastChannel (default: true in browsers) */
39
39
  crossTabSync?: boolean;
40
- /**
41
- * "Cookie-only" mode for web apps that rely exclusively on the
42
- * `oxy_rt_${authuser}` httpOnly refresh cookies and refuse to fall back
43
- * to the legacy localStorage token/refresh-token path.
44
- *
45
- * - `false` (default): `initialize()` tries `restoreFromCookies()` first;
46
- * if no accounts are restored it falls back to the legacy localStorage
47
- * path (`oxy_access_token` / `oxy_session`).
48
- * - `true`: `initialize()` ONLY uses `restoreFromCookies()`. No token /
49
- * refresh-token / session JSON is read from or written to localStorage.
50
- * This is the secure default for apps that ship the cookie path end-to-
51
- * end and want to guarantee no tokens leak to JS-accessible storage.
52
- */
53
- cookieOnly?: boolean;
54
40
  }
55
41
  /**
56
42
  * AuthManager - Centralized authentication management.
@@ -82,6 +68,7 @@ export declare class AuthManager {
82
68
  private storage;
83
69
  private listeners;
84
70
  private currentUser;
71
+ private currentAuthMethod;
85
72
  private refreshTimer;
86
73
  private refreshPromise;
87
74
  private config;
@@ -89,8 +76,6 @@ export declare class AuthManager {
89
76
  private _lastKnownAccessToken;
90
77
  /** BroadcastChannel for coordinating token refreshes across browser tabs. */
91
78
  private _broadcastChannel;
92
- /** Set to true when another tab broadcasts a successful refresh, so this tab can skip its own. */
93
- private _otherTabRefreshed;
94
79
  /**
95
80
  * Identifier for this AuthManager instance (≈ "this tab"). Random hex
96
81
  * generated at construction; advertised in every outgoing broadcast and
@@ -216,13 +201,11 @@ export declare class AuthManager {
216
201
  * @param method - Auth method used
217
202
  */
218
203
  handleAuthSuccess(session: SessionLoginResponse, method?: AuthMethod): Promise<void>;
219
- /**
220
- * Setup automatic token refresh.
221
- */
222
- private setupTokenRefresh;
223
204
  /**
224
205
  * Refresh the access token. Deduplicates concurrent calls so only one
225
- * refresh request is in-flight at a time.
206
+ * refresh request is in-flight at a time. The only refresh authority is the
207
+ * active httpOnly refresh-cookie slot; this method never reads access tokens
208
+ * from storage.
226
209
  */
227
210
  refreshToken(): Promise<boolean>;
228
211
  private _doRefreshToken;
@@ -231,7 +214,8 @@ export declare class AuthManager {
231
214
  */
232
215
  signOut(): Promise<void>;
233
216
  /**
234
- * Clear session data from storage.
217
+ * Clear local cookie-path state. The only persisted AuthManager value is the
218
+ * active numeric slot; tokens and user objects are intentionally memory-only.
235
219
  */
236
220
  private clearSession;
237
221
  /**
@@ -243,7 +227,8 @@ export declare class AuthManager {
243
227
  */
244
228
  isAuthenticated(): boolean;
245
229
  /**
246
- * Get a valid access token, refreshing automatically if expired or expiring soon.
230
+ * Get a valid access token, refreshing automatically if expired or expiring
231
+ * soon. The token is read from memory only.
247
232
  */
248
233
  getAccessToken(): Promise<string | null>;
249
234
  /**
@@ -253,21 +238,13 @@ export declare class AuthManager {
253
238
  /**
254
239
  * Initialize auth state on app startup.
255
240
  *
256
- * Order of operations:
257
- * 1. Try the cookie path via `restoreFromCookies()`. This is the
258
- * preferred path because the httpOnly refresh cookies are
259
- * cross-tab, persist across hard reloads, and don't expose any
260
- * refresh-token material to JS.
261
- * 2. If the cookie path yielded zero accounts AND `cookieOnly` is
262
- * `false`, fall back to the legacy localStorage path
263
- * (`oxy_access_token` / `oxy_session`) for backwards compatibility
264
- * with apps that haven't migrated to the cookie endpoint yet.
265
- * 3. If `cookieOnly` is `true`, skip the legacy fallback entirely.
266
- * This guarantees no tokens or refresh tokens are ever read from
267
- * or written to JS-accessible storage.
241
+ * Only the cookie path is authoritative. `restoreFromCookies()` refreshes
242
+ * the httpOnly `oxy_rt_${authuser}` slots through `/auth/refresh-all`,
243
+ * plants the active access token in memory, and returns the active user.
244
+ * No access token, refresh token, or session JSON is read from localStorage.
268
245
  *
269
- * Returns the active user on success, or `null` when neither path
270
- * restored a session.
246
+ * Returns the active user on success, or `null` when no cookie-backed
247
+ * account was restored.
271
248
  */
272
249
  initialize(options?: RestoreFromCookiesOptions): Promise<MinimalUserData | null>;
273
250
  /**
@@ -290,15 +267,14 @@ export declare class AuthManager {
290
267
  private clearActiveAuthuser;
291
268
  /**
292
269
  * Build a `MinimalUserData` from a `RefreshAllAccount`. Returns `null` when
293
- * the wire entry has no user shape (legacy `/auth/refresh` fallback) the
294
- * AuthManager's caller is expected to hydrate via `/users/me` in that
295
- * case.
270
+ * the wire entry has no user shape; the AuthManager's caller is expected to
271
+ * hydrate via `/users/me` in that case.
296
272
  */
297
273
  private static toMinimalUser;
298
274
  /**
299
275
  * Hydrate the user shape for a slot whose AuthManagerAccount currently has
300
- * `user: null` (legacy refresh fallback, or a switch onto a previously
301
- * unknown slot). Calls `/users/me` with the slot's freshly-planted access
276
+ * `user: null` (for example, a switch onto a previously unknown slot). Calls
277
+ * `/users/me` with the slot's freshly-planted access
302
278
  * token already on the HTTP client; merges the result back into the
303
279
  * registry entry. Network failures are non-fatal — the slot remains with
304
280
  * `user: null` and the UI is expected to render the public-key fallback
@@ -326,9 +302,7 @@ export declare class AuthManager {
326
302
  * Calls `oxyServices.refreshAllSessions()` (`POST /auth/refresh-all` with
327
303
  * `credentials: 'include'`). The server rotates every presented
328
304
  * `oxy_rt_${authuser}` cookie in parallel and returns one entry per
329
- * VALID slot. The SDK transparently falls back to the legacy single-slot
330
- * `/auth/refresh` against older servers (handled inside
331
- * `refreshAllSessions`).
305
+ * valid slot.
332
306
  *
333
307
  * Plants the active account's access token on the shared HTTP client;
334
308
  * sibling slots' tokens stay in the in-memory registry so a later
@@ -374,16 +348,14 @@ export declare class AuthManager {
374
348
  *
375
349
  * Calls `oxyServices.logoutAllSessionsViaCookie()`: server-side revokes
376
350
  * every presented family and `Set-Cookie`s an immediate expiry for every
377
- * recognised `oxy_rt_${n}` slot AND the legacy `oxy_rt` cookie. The
378
- * in-memory registry is wiped, the active slot is cleared, and the
379
- * persisted `oxy_active_authuser` is removed so the next cold boot
380
- * starts fresh.
351
+ * recognised `oxy_rt_${n}` slot. The in-memory registry is wiped, the active
352
+ * slot is cleared, and the persisted `oxy_active_authuser` is removed so the
353
+ * next cold boot starts fresh.
381
354
  */
382
355
  signOutAllViaCookies(): Promise<void>;
383
356
  /**
384
- * Schedule an auto-refresh for the cookie path on the active slot. Reuses
385
- * the same single `refreshTimer` as the legacy path (the AuthManager has
386
- * exactly ONE active slot at a time, so one timer suffices).
357
+ * Schedule an auto-refresh for the cookie path on the active slot. The
358
+ * AuthManager has exactly one active slot at a time, so one timer suffices.
387
359
  */
388
360
  private setupCookieRefresh;
389
361
  /**
@@ -392,6 +364,7 @@ export declare class AuthManager {
392
364
  * signature when minting the token. Returns `null` on malformed input.
393
365
  */
394
366
  private static decodeSessionIdFromAccessToken;
367
+ private static decodeAuthuserFromAccessToken;
395
368
  /**
396
369
  * Destroy the auth manager and clean up resources.
397
370
  */
@@ -28,13 +28,10 @@ export interface AuthManagerAccount {
28
28
  * Projected user shape from the wire (username/avatar/color/email).
29
29
  *
30
30
  * `null` when a refresh-via-cookie planted a fresh access token for a slot
31
- * that the AuthManager has no prior in-memory user metadata for e.g. the
32
- * legacy `/auth/refresh` 404 fallback path inside `refreshAllSessions`, or
33
- * a `switchAuthuser` against a slot that wasn't present in the previous
34
- * `restoreFromCookies` snapshot. Callers (or the AuthManager itself) are
35
- * expected to hydrate the user shape via `getCurrentUser()` after the token
36
- * is planted; the chooser UI must render the public-key fallback handle
37
- * until the hydration completes.
31
+ * that the AuthManager has no prior in-memory user metadata for. Callers (or
32
+ * the AuthManager itself) are expected to hydrate the user shape via
33
+ * `getCurrentUser()` after the token is planted; the chooser UI must render
34
+ * the public-key fallback handle until the hydration completes.
38
35
  */
39
36
  user: RefreshAllAccountUser | null;
40
37
  /** Currently-valid access token for this slot (in-memory only). */
@@ -75,8 +72,7 @@ export interface RestoreFromCookiesOptions {
75
72
  /**
76
73
  * Outcome of `AuthManager.switchAuthuser()`.
77
74
  *
78
- * Mirrors the wire `RefreshCookieResponse` but with `authuser` narrowed to
79
- * `number` (the SDK boundary normalises the legacy `null` slot to `0`).
75
+ * Mirrors the wire `RefreshCookieResponse`.
80
76
  */
81
77
  export interface SwitchAuthuserResult {
82
78
  accessToken: string;
@@ -5,8 +5,7 @@
5
5
  * selects the best authentication method based on browser capabilities:
6
6
  *
7
7
  * 1. FedCM (if supported) - Modern, Google-style browser-native auth
8
- * 2. Popup (fallback) - OAuth2-style popup window
9
- * 3. Redirect (final fallback) - Traditional full-page redirect
8
+ * 2. Redirect (fallback) - Tokenless central SSO full-page redirect
10
9
  *
11
10
  * Usage:
12
11
  * ```typescript
@@ -17,8 +16,8 @@
17
16
  * // Automatic method selection
18
17
  * const session = await auth.signIn();
19
18
  *
20
- * // Or use specific method
21
- * const session = await auth.signInWithPopup();
19
+ * // Or use a specific method
20
+ * auth.signInWithRedirect();
22
21
  * ```
23
22
  */
24
23
  import type { OxyServices } from './OxyServices';
@@ -28,10 +27,9 @@ export interface CrossDomainAuthOptions {
28
27
  * Preferred authentication method
29
28
  * - 'auto': Automatically select best method (default)
30
29
  * - 'fedcm': Use FedCM (browser-native)
31
- * - 'popup': Use popup window
32
30
  * - 'redirect': Use full-page redirect
33
31
  */
34
- method?: 'auto' | 'fedcm' | 'popup' | 'redirect';
32
+ method?: 'auto' | 'fedcm' | 'redirect';
35
33
  /**
36
34
  * Custom redirect URI (for redirect method)
37
35
  */
@@ -40,24 +38,10 @@ export interface CrossDomainAuthOptions {
40
38
  * Whether to open signup page instead of login
41
39
  */
42
40
  isSignup?: boolean;
43
- /**
44
- * Popup window dimensions (for popup method)
45
- */
46
- popupDimensions?: {
47
- width?: number;
48
- height?: number;
49
- };
50
41
  /**
51
42
  * Callback when auth method is selected
52
43
  */
53
- onMethodSelected?: (method: 'fedcm' | 'popup' | 'redirect') => void;
54
- /**
55
- * A popup window the caller already opened SYNCHRONOUSLY in the user-gesture
56
- * handler. Forwarded to `OxyServices.signInWithPopup` so the popup is not
57
- * blocked by Chrome after any prior `await` (FedCM / silent SSO) has
58
- * consumed the transient user activation. See `OxyServices.openBlankPopup`.
59
- */
60
- popup?: Window | null;
44
+ onMethodSelected?: (method: 'fedcm' | 'redirect') => void;
61
45
  }
62
46
  export declare class CrossDomainAuth {
63
47
  private oxyServices;
@@ -67,21 +51,12 @@ export declare class CrossDomainAuth {
67
51
  *
68
52
  * Tries methods in this order:
69
53
  * 1. FedCM (if supported and not in private browsing)
70
- * 2. Popup (if not blocked)
71
- * 3. Redirect (always works)
54
+ * 2. Redirect (always works)
72
55
  *
73
56
  * @param options - Authentication options
74
57
  * @returns Session with user data and access token
75
58
  */
76
59
  signIn(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse | null>;
77
- /**
78
- * Close a caller-supplied popup window that is no longer needed (e.g. the
79
- * resolved auth method didn't end up using it). Safe against null / already
80
- * closed handles.
81
- *
82
- * @private
83
- */
84
- private closeOrphanPopup;
85
60
  /**
86
61
  * Automatic sign-in with progressive enhancement
87
62
  *
@@ -91,15 +66,9 @@ export declare class CrossDomainAuth {
91
66
  /**
92
67
  * Sign in using FedCM (Federated Credential Management)
93
68
  *
94
- * Best method - browser-native, no popups, Google-like experience
69
+ * Best method - browser-native, Google-like experience
95
70
  */
96
71
  signInWithFedCM(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse>;
97
- /**
98
- * Sign in using popup window
99
- *
100
- * Good method - preserves app state, no full page reload
101
- */
102
- signInWithPopup(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse>;
103
72
  /**
104
73
  * Sign in using full-page redirect
105
74
  *
@@ -116,25 +85,18 @@ export declare class CrossDomainAuth {
116
85
  * Silent sign-in (check for existing session)
117
86
  *
118
87
  * Tries to automatically sign in without user interaction.
119
- * Works with both FedCM and popup/iframe methods.
88
+ * Works with FedCM and iframe-based silent auth.
120
89
  *
121
90
  * @returns Session if user is already signed in, null otherwise
122
91
  */
123
92
  silentSignIn(): Promise<SessionLoginResponse | null>;
124
93
  /**
125
- * Restore session from storage
94
+ * Restore session from storage.
126
95
  *
127
- * For redirect method - restores previously authenticated session from localStorage
96
+ * Access tokens are no longer persisted in browser storage; providers restore
97
+ * through refresh cookies / SSO code exchange instead.
128
98
  */
129
99
  restoreSession(): boolean;
130
- /**
131
- * Open a blank popup SYNCHRONOUSLY (call from a raw user-gesture handler
132
- * BEFORE any `await`). Returns `null` if the popup was blocked. Pass the
133
- * handle into `signIn({ popup })` / `signInWithPopup({ popup })` so the
134
- * popup is not blocked by Chrome after any prior `await` consumed the
135
- * transient user activation. Delegates to `OxyServices.openBlankPopup`.
136
- */
137
- openBlankPopup(width?: number, height?: number): Window | null;
138
100
  /**
139
101
  * Check if FedCM is supported in current browser
140
102
  */
@@ -145,7 +107,7 @@ export declare class CrossDomainAuth {
145
107
  * @returns Recommended method name and reason
146
108
  */
147
109
  getRecommendedMethod(): {
148
- method: 'fedcm' | 'popup' | 'redirect';
110
+ method: 'fedcm' | 'redirect';
149
111
  reason: string;
150
112
  };
151
113
  /**
@@ -153,8 +115,7 @@ export declare class CrossDomainAuth {
153
115
  *
154
116
  * This handles:
155
117
  * 1. Redirect callback (if returning from auth.oxy.so)
156
- * 2. Session restoration (from localStorage)
157
- * 3. Silent sign-in (check for existing SSO session)
118
+ * 2. Silent sign-in (check for existing SSO session)
158
119
  *
159
120
  * @returns Session if user is authenticated, null otherwise
160
121
  */
@@ -13,6 +13,8 @@
13
13
  * - Request queuing
14
14
  */
15
15
  import type { OxyConfig } from './models/interfaces';
16
+ export type AuthRefreshReason = 'preflight' | 'response-401';
17
+ export type AuthRefreshHandler = (reason: AuthRefreshReason) => Promise<string | null>;
16
18
  export interface RequestOptions {
17
19
  cache?: boolean;
18
20
  cacheTTL?: number;
@@ -49,13 +51,12 @@ export declare class HttpService {
49
51
  private config;
50
52
  private tokenRefreshPromise;
51
53
  private tokenRefreshCooldownUntil;
52
- private _onTokenRefreshed;
54
+ private authRefreshHandler;
53
55
  /**
54
56
  * Fan-out listeners notified on EVERY access-token change on this instance:
55
- * explicit `setTokens`, `clearTokens`, a successful silent refresh, and the
56
- * internal 401-driven clear. Unlike the single-slot `_onTokenRefreshed`
57
- * (owned by AuthManager for the refresh path only), this is a Set so multiple
58
- * independent observers can mirror token state without clobbering each other.
57
+ * explicit `setTokens`, `clearTokens`, an AuthManager-owned refresh, and the
58
+ * internal 401-driven clear. This is a Set so multiple independent observers
59
+ * can mirror token state without clobbering each other.
59
60
  *
60
61
  * Each listener receives the resulting access token, or `null` when cleared.
61
62
  */
@@ -171,7 +172,7 @@ export declare class HttpService {
171
172
  * Get auth header with automatic token refresh
172
173
  */
173
174
  private getAuthHeader;
174
- private _refreshTokenFromSession;
175
+ private refreshAccessToken;
175
176
  /**
176
177
  * Unwrap standardized API response format
177
178
  */
@@ -187,8 +188,8 @@ export declare class HttpService {
187
188
  delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'method' | 'url'>): Promise<T>;
188
189
  setActingAs(userId: string | null): void;
189
190
  getActingAs(): string | null;
190
- setTokens(accessToken: string, refreshToken?: string): void;
191
- set onTokenRefreshed(callback: ((accessToken: string) => void) | null);
191
+ setTokens(accessToken: string): void;
192
+ setAuthRefreshHandler(handler: AuthRefreshHandler | null): void;
192
193
  clearTokens(): void;
193
194
  /**
194
195
  * Subscribe to access-token changes on this instance.
@@ -82,7 +82,7 @@ export declare class OxyServicesBase {
82
82
  /**
83
83
  * Set authentication tokens
84
84
  */
85
- setTokens(accessToken: string, refreshToken?: string): void;
85
+ setTokens(accessToken: string): void;
86
86
  /**
87
87
  * Clear stored authentication tokens
88
88
  */
@@ -60,7 +60,7 @@ import { type OxyConfig } from './OxyServices.base';
60
60
  import { OxyAuthenticationError, OxyAuthenticationTimeoutError } from './OxyServices.errors';
61
61
  import type { SessionLoginResponse } from './models/session';
62
62
  import type { FedCMAuthOptions, FedCMConfig } from './mixins/OxyServices.fedcm';
63
- import type { PopupAuthOptions } from './mixins/OxyServices.popup';
63
+ import type { SilentAuthOptions } from './mixins/OxyServices.silent';
64
64
  import type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
65
65
  import { composeOxyServices } from './mixins';
66
66
  /**
@@ -116,15 +116,9 @@ export interface OxyServices extends InstanceType<ReturnType<typeof composeOxySe
116
116
  silentSignInWithFedCM(): Promise<SessionLoginResponse | null>;
117
117
  revokeFedCMCredential(): Promise<void>;
118
118
  getFedCMConfig(): FedCMConfig;
119
- signInWithPopup(options?: PopupAuthOptions): Promise<SessionLoginResponse>;
120
- signUpWithPopup(options?: PopupAuthOptions): Promise<SessionLoginResponse>;
121
- /**
122
- * Open a blank popup SYNCHRONOUSLY (call from a raw user-gesture handler
123
- * BEFORE any `await`). Returns `null` if the popup was blocked. Pass the
124
- * handle into `signInWithPopup({ popup })` to navigate it to auth.oxy.so
125
- * after the async portion of the sign-in flow runs.
126
- */
127
- openBlankPopup(width?: number, height?: number): Window | null;
119
+ resolveAuthUrl(): string;
120
+ silentSignIn(options?: SilentAuthOptions): Promise<SessionLoginResponse | null>;
121
+ waitForIframeAuth(iframe: HTMLIFrameElement, timeout: number, expectedOrigin: string): Promise<SessionLoginResponse | null>;
128
122
  signInWithRedirect(options?: RedirectAuthOptions): void;
129
123
  signUpWithRedirect(options?: RedirectAuthOptions): void;
130
124
  exchangeSsoCode(code: string): Promise<SessionLoginResponse>;
@@ -25,7 +25,7 @@ export type { AuthManagerAccount, RestoreFromCookiesResult, RestoreFromCookiesOp
25
25
  export { CrossDomainAuth, createCrossDomainAuth } from './CrossDomainAuth';
26
26
  export type { CrossDomainAuthOptions } from './CrossDomainAuth';
27
27
  export type { FedCMAuthOptions, FedCMConfig, AuthorizedApp } from './mixins/OxyServices.fedcm';
28
- export type { PopupAuthOptions } from './mixins/OxyServices.popup';
28
+ export type { SilentAuthOptions } from './mixins/OxyServices.silent';
29
29
  export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
30
30
  export { ServiceCredentialMismatchError } from './mixins/OxyServices.auth';
31
31
  export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
@@ -45,7 +45,7 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
45
45
  hitRate: number;
46
46
  };
47
47
  getCloudURL(): string;
48
- setTokens(accessToken: string, refreshToken?: string): void;
48
+ setTokens(accessToken: string): void;
49
49
  clearTokens(): void;
50
50
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
51
51
  _cachedUserId: string | null | undefined;
@@ -81,7 +81,7 @@ export declare function OxyServicesAppDataMixin<T extends typeof OxyServicesBase
81
81
  hitRate: number;
82
82
  };
83
83
  getCloudURL(): string;
84
- setTokens(accessToken: string, refreshToken?: string): void;
84
+ setTokens(accessToken: string): void;
85
85
  clearTokens(): void;
86
86
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
87
87
  _cachedUserId: string | null | undefined;
@@ -389,7 +389,7 @@ export declare function OxyServicesApplicationsMixin<T extends typeof OxyService
389
389
  hitRate: number;
390
390
  };
391
391
  getCloudURL(): string;
392
- setTokens(accessToken: string, refreshToken?: string): void;
392
+ setTokens(accessToken: string): void;
393
393
  clearTokens(): void;
394
394
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
395
395
  _cachedUserId: string | null | undefined;
@@ -118,7 +118,7 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
118
118
  hitRate: number;
119
119
  };
120
120
  getCloudURL(): string;
121
- setTokens(accessToken: string, refreshToken?: string): void;
121
+ setTokens(accessToken: string): void;
122
122
  clearTokens(): void;
123
123
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
124
124
  _cachedUserId: string | null | undefined;
@@ -23,8 +23,8 @@ export interface RefreshAllOptions {
23
23
  * or unreachable endpoint with no useful answer coming back. As one step of
24
24
  * the ordered cold-boot sequence, a stalled refresh is dead latency in front
25
25
  * of the steps that actually hold the answer. A bounded abort lets cold boot
26
- * fall through quickly. Omit (or pass `0`/negative) to wait indefinitely
27
- * (the legacy behaviour). The abort is treated identically to a 401 — the
26
+ * fall through quickly. Omit (or pass `0`/negative) to wait indefinitely.
27
+ * The abort is treated identically to a 401 — the
28
28
  * "not signed in on this device" path — never an error.
29
29
  */
30
30
  timeout?: number;
@@ -245,18 +245,6 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
245
245
  sessionId: string;
246
246
  user: User | null;
247
247
  }>>;
248
- /**
249
- * Get access token by session ID
250
- *
251
- * SECURITY: this endpoint requires the caller to already hold a
252
- * bearer token whose user owns the referenced session (C1 hardening
253
- * in the API). For the device-flow / QR sign-in case where the
254
- * client has no bearer token yet, use `claimSessionByToken` instead.
255
- */
256
- getTokenBySession(sessionId: string): Promise<{
257
- accessToken: string;
258
- expiresAt: string;
259
- }>;
260
248
  /**
261
249
  * Exchange a device-flow sessionToken for the first access token.
262
250
  *
@@ -282,7 +270,6 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
282
270
  deviceFingerprint?: string;
283
271
  }): Promise<{
284
272
  accessToken: string;
285
- refreshToken: string;
286
273
  sessionId: string;
287
274
  deviceId: string;
288
275
  expiresAt: string;
@@ -293,19 +280,14 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
293
280
  * (Google-style multi-account rebuild).
294
281
  *
295
282
  * Calls `POST {sessionBaseUrl}/auth/refresh-all` with `credentials: 'include'`
296
- * and NO bearer. The browser attaches every `oxy_rt*` cookie it has; the
297
- * server rotates each in parallel and returns one entry per VALID account.
283
+ * and NO bearer. The browser attaches every indexed `oxy_rt_${authuser}`
284
+ * cookie it has; the server rotates each in parallel and returns one entry
285
+ * per VALID account.
298
286
  *
299
287
  * Failure handling:
300
288
  * - 401 → no signed-in accounts on this device → returns `{ accounts: [] }`
301
289
  * (NOT an error; this is the cold-boot "not signed in" path).
302
- * - 404 → server is older than the multi-account endpoint. We fall back to
303
- * `POST /auth/refresh` (single-slot) and wrap its response in the
304
- * refresh-all shape so callers can treat the two paths uniformly. The
305
- * fallback entry has `authuser: 0` (the legacy slot maps to slot 0 by
306
- * convention) and a minimal `user` shape — consumers needing the full
307
- * user must fetch it separately. Always exactly one account in this
308
- * shape.
290
+ * - 404 → endpoint not deployed returns `{ accounts: [] }`.
309
291
  * - Any other non-2xx → throws via `handleError`.
310
292
  *
311
293
  * The refresh cookie itself never enters JS — only the rotated access
@@ -318,9 +300,8 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
318
300
  *
319
301
  * When `authuser` is provided, the server rotates ONLY that slot
320
302
  * (`oxy_rt_${authuser}`) — sibling accounts on the same device stay
321
- * untouched. When omitted, the server picks the lowest indexed slot
322
- * present (legacy fallback applies). The refresh cookie itself never
323
- * enters JS.
303
+ * untouched. When omitted, the server picks the lowest indexed slot present.
304
+ * The refresh cookie itself never enters JS.
324
305
  *
325
306
  * Returns `null` on 401 (no cookie / expired / reused) so the caller can
326
307
  * fall through cleanly to the unauthenticated path.
@@ -344,9 +325,7 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
344
325
  logoutAllSessionsViaCookie(): Promise<void>;
345
326
  /**
346
327
  * Internal: raw `POST /auth/refresh[?authuser=N]` call returning the
347
- * minted access token. Returns `null` on 401 / non-2xx. Used as both the
348
- * implementation of `refreshTokenViaCookie` and the legacy fallback for
349
- * `refreshAllSessions` against older servers.
328
+ * minted access token. Returns `null` on 401 / non-2xx.
350
329
  *
351
330
  * @internal
352
331
  */
@@ -437,7 +416,7 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
437
416
  hitRate: number;
438
417
  };
439
418
  getCloudURL(): string;
440
- setTokens(accessToken: string, refreshToken?: string): void;
419
+ setTokens(accessToken: string): void;
441
420
  clearTokens(): void;
442
421
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
443
422
  _cachedUserId: string | null | undefined;
@@ -73,7 +73,7 @@ export declare function OxyServicesContactsMixin<T extends typeof OxyServicesBas
73
73
  hitRate: number;
74
74
  };
75
75
  getCloudURL(): string;
76
- setTokens(accessToken: string, refreshToken?: string): void;
76
+ setTokens(accessToken: string): void;
77
77
  clearTokens(): void;
78
78
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
79
79
  _cachedUserId: string | null | undefined;
@@ -75,7 +75,7 @@ export declare function OxyServicesDevicesMixin<T extends typeof OxyServicesBase
75
75
  hitRate: number;
76
76
  };
77
77
  getCloudURL(): string;
78
- setTokens(accessToken: string, refreshToken?: string): void;
78
+ setTokens(accessToken: string): void;
79
79
  clearTokens(): void;
80
80
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
81
81
  _cachedUserId: string | null | undefined;
@@ -202,7 +202,7 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
202
202
  hitRate: number;
203
203
  };
204
204
  getCloudURL(): string;
205
- setTokens(accessToken: string, refreshToken?: string): void;
205
+ setTokens(accessToken: string): void;
206
206
  clearTokens(): void;
207
207
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
208
208
  _cachedUserId: string | null | undefined;
@@ -42,7 +42,7 @@ interface FedCMTokenResult {
42
42
  * - Firefox: Not yet supported (fallback required)
43
43
  *
44
44
  * Key Features:
45
- * - No redirects or popups required
45
+ * - No redirects or secondary windows required
46
46
  * - Browser-native UI prompts
47
47
  * - Privacy-preserving (IdP can't track users)
48
48
  * - Automatic SSO across domains
@@ -62,7 +62,7 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
62
62
  *
63
63
  * This provides a Google-style authentication experience:
64
64
  * - Browser shows native "Sign in with Oxy" prompt
65
- * - No redirect or popup required
65
+ * - No redirect or secondary window required
66
66
  * - User approves → credential exchange happens in browser
67
67
  * - All apps automatically get SSO after first sign-in
68
68
  *
@@ -76,8 +76,8 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
76
76
  * const session = await oxyServices.signInWithFedCM();
77
77
  * console.log('Signed in:', session.user);
78
78
  * } catch (error) {
79
- * // Fallback to popup or redirect auth
80
- * await oxyServices.signInWithPopup();
79
+ * // Fallback to redirect auth
80
+ * oxyServices.signInWithRedirect();
81
81
  * }
82
82
  * ```
83
83
  */
@@ -277,7 +277,7 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
277
277
  hitRate: number;
278
278
  };
279
279
  getCloudURL(): string;
280
- setTokens(accessToken: string, refreshToken?: string): void;
280
+ setTokens(accessToken: string): void;
281
281
  clearTokens(): void;
282
282
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
283
283
  _cachedUserId: string | null | undefined;
@@ -60,7 +60,7 @@ export declare function OxyServicesLanguageMixin<T extends typeof OxyServicesBas
60
60
  hitRate: number;
61
61
  };
62
62
  getCloudURL(): string;
63
- setTokens(accessToken: string, refreshToken?: string): void;
63
+ setTokens(accessToken: string): void;
64
64
  clearTokens(): void;
65
65
  onTokensChanged(listener: (accessToken: string | null) => void): () => void;
66
66
  _cachedUserId: string | null | undefined;