@oxyhq/core 3.4.0 → 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 +25 -3
  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
@@ -103,7 +103,9 @@
103
103
  "createAccount": "创建账户",
104
104
  "signIn": "登录",
105
105
  "verify": "验证",
106
- "resetPassword": "重置密码"
106
+ "resetPassword": "重置密码",
107
+ "signedOut": "已退出",
108
+ "close": "关闭"
107
109
  },
108
110
  "links": {
109
111
  "recoverAccount": "恢复您的账户",
@@ -115,7 +117,10 @@
115
117
  "password": "密码",
116
118
  "confirmPassword": "确认密码"
117
119
  },
118
- "revoke": "Revoke"
120
+ "revoke": "Revoke",
121
+ "errors": {
122
+ "signOutAllFailed": "退出所有账户时出现问题。请重试。"
123
+ }
119
124
  },
120
125
  "notifications": {
121
126
  "title": "Notifications",
@@ -198,5 +203,16 @@
198
203
  "revoked": "Revoked access for {{name}}",
199
204
  "revokeFailed": "Failed to revoke access"
200
205
  }
206
+ },
207
+ "accountMenu": {
208
+ "label": "账户菜单",
209
+ "manage": "管理您的 Oxy 账户",
210
+ "addAnother": "添加其他账户",
211
+ "signOutAll": "退出所有账户",
212
+ "open": "账户菜单",
213
+ "openHint": "打开账户菜单",
214
+ "openWithUser": "{{name}} 的账户菜单",
215
+ "switching": "正在切换账户…",
216
+ "signOutAccount": "退出 {{name}}"
201
217
  }
202
218
  }
package/src/index.ts CHANGED
@@ -46,7 +46,7 @@ export type {
46
46
  export { CrossDomainAuth, createCrossDomainAuth } from './CrossDomainAuth';
47
47
  export type { CrossDomainAuthOptions } from './CrossDomainAuth';
48
48
  export type { FedCMAuthOptions, FedCMConfig, AuthorizedApp } from './mixins/OxyServices.fedcm';
49
- export type { PopupAuthOptions } from './mixins/OxyServices.popup';
49
+ export type { SilentAuthOptions } from './mixins/OxyServices.silent';
50
50
  export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
51
51
  export { ServiceCredentialMismatchError } from './mixins/OxyServices.auth';
52
52
  export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
@@ -34,8 +34,8 @@ export interface RefreshAllOptions {
34
34
  * or unreachable endpoint with no useful answer coming back. As one step of
35
35
  * the ordered cold-boot sequence, a stalled refresh is dead latency in front
36
36
  * of the steps that actually hold the answer. A bounded abort lets cold boot
37
- * fall through quickly. Omit (or pass `0`/negative) to wait indefinitely
38
- * (the legacy behaviour). The abort is treated identically to a 401 — the
37
+ * fall through quickly. Omit (or pass `0`/negative) to wait indefinitely.
38
+ * The abort is treated identically to a 401 — the
39
39
  * "not signed in on this device" path — never an error.
40
40
  */
41
41
  timeout?: number;
@@ -445,14 +445,10 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
445
445
  // Plant the freshly-minted tokens, mirroring `claimSessionByToken`.
446
446
  // `/auth/verify` returns the first access token (and refresh token) in
447
447
  // its body, so installing it here means callers get an authenticated
448
- // client without a second round-trip and, critically, without
449
- // falling back to the bearer-protected `GET /session/token/:sessionId`
450
- // (C1 hardening), which 401s for a brand-new identity that has no
451
- // bearer yet. `accessToken`/`refreshToken` are optional on
452
- // SessionLoginResponse; only plant when an access token is present and
453
- // default the refresh token to an empty string.
448
+ // client without a second round-trip. Refresh stays in the httpOnly
449
+ // cookie slot set by the API.
454
450
  if (res?.accessToken) {
455
- this.setTokens(res.accessToken, res.refreshToken ?? '');
451
+ this.setTokens(res.accessToken);
456
452
  }
457
453
 
458
454
  return res;
@@ -533,31 +529,6 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
533
529
  }
534
530
  }
535
531
 
536
- /**
537
- * Get access token by session ID
538
- *
539
- * SECURITY: this endpoint requires the caller to already hold a
540
- * bearer token whose user owns the referenced session (C1 hardening
541
- * in the API). For the device-flow / QR sign-in case where the
542
- * client has no bearer token yet, use `claimSessionByToken` instead.
543
- */
544
- async getTokenBySession(sessionId: string): Promise<{ accessToken: string; expiresAt: string }> {
545
- try {
546
- const res = await this.makeRequest<{ accessToken: string; expiresAt: string }>(
547
- 'GET',
548
- `/session/token/${sessionId}`,
549
- undefined,
550
- { cache: false, retry: false }
551
- );
552
-
553
- this.setTokens(res.accessToken);
554
-
555
- return res;
556
- } catch (error) {
557
- throw this.handleError(error);
558
- }
559
- }
560
-
561
532
  /**
562
533
  * Exchange a device-flow sessionToken for the first access token.
563
534
  *
@@ -584,7 +555,6 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
584
555
  options: { deviceFingerprint?: string } = {}
585
556
  ): Promise<{
586
557
  accessToken: string;
587
- refreshToken: string;
588
558
  sessionId: string;
589
559
  deviceId: string;
590
560
  expiresAt: string;
@@ -593,7 +563,6 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
593
563
  try {
594
564
  const res = await this.makeRequest<{
595
565
  accessToken: string;
596
- refreshToken: string;
597
566
  sessionId: string;
598
567
  deviceId: string;
599
568
  expiresAt: string;
@@ -608,7 +577,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
608
577
  { cache: false, retry: false }
609
578
  );
610
579
 
611
- this.setTokens(res.accessToken, res.refreshToken);
580
+ this.setTokens(res.accessToken);
612
581
 
613
582
  return res;
614
583
  } catch (error) {
@@ -621,19 +590,14 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
621
590
  * (Google-style multi-account rebuild).
622
591
  *
623
592
  * Calls `POST {sessionBaseUrl}/auth/refresh-all` with `credentials: 'include'`
624
- * and NO bearer. The browser attaches every `oxy_rt*` cookie it has; the
625
- * server rotates each in parallel and returns one entry per VALID account.
593
+ * and NO bearer. The browser attaches every indexed `oxy_rt_${authuser}`
594
+ * cookie it has; the server rotates each in parallel and returns one entry
595
+ * per VALID account.
626
596
  *
627
597
  * Failure handling:
628
598
  * - 401 → no signed-in accounts on this device → returns `{ accounts: [] }`
629
599
  * (NOT an error; this is the cold-boot "not signed in" path).
630
- * - 404 → server is older than the multi-account endpoint. We fall back to
631
- * `POST /auth/refresh` (single-slot) and wrap its response in the
632
- * refresh-all shape so callers can treat the two paths uniformly. The
633
- * fallback entry has `authuser: 0` (the legacy slot maps to slot 0 by
634
- * convention) and a minimal `user` shape — consumers needing the full
635
- * user must fetch it separately. Always exactly one account in this
636
- * shape.
600
+ * - 404 → endpoint not deployed returns `{ accounts: [] }`.
637
601
  * - Any other non-2xx → throws via `handleError`.
638
602
  *
639
603
  * The refresh cookie itself never enters JS — only the rotated access
@@ -682,22 +646,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
682
646
  }
683
647
 
684
648
  if (response.status === 404) {
685
- // Legacy single-account refresh fallback. Wrap the response so the
686
- // caller can treat both paths identically.
687
- const legacy = await this._refreshCookieRaw();
688
- if (!legacy) {
689
- return { accounts: [] };
690
- }
691
- const fallbackAccount: RefreshAllAccount = {
692
- authuser: 0,
693
- accessToken: legacy.accessToken,
694
- expiresAt: legacy.expiresAt,
695
- sessionId: this._decodeSessionIdFromAccessToken(legacy.accessToken) ?? '',
696
- // Legacy /auth/refresh does NOT project the user shape; the caller
697
- // (AuthManager) is expected to hydrate via /users/me after planting.
698
- user: null,
699
- };
700
- return { accounts: [fallbackAccount] };
649
+ return { accounts: [] };
701
650
  }
702
651
 
703
652
  if (!response.ok) {
@@ -715,7 +664,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
715
664
  continue;
716
665
  }
717
666
  const e = entry as {
718
- authuser?: number | null;
667
+ authuser?: number;
719
668
  accessToken?: string;
720
669
  expiresAt?: string;
721
670
  sessionId?: string;
@@ -728,11 +677,11 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
728
677
  if (!userId || !e.user.username) {
729
678
  continue;
730
679
  }
731
- // Normalise the legacy un-suffixed cookie (`authuser: null` on the
732
- // wire) to slot 0. The SDK surface always operates on numeric indices.
733
- const authuser = typeof e.authuser === 'number' ? e.authuser : 0;
680
+ if (typeof e.authuser !== 'number') {
681
+ continue;
682
+ }
734
683
  accounts.push({
735
- authuser,
684
+ authuser: e.authuser,
736
685
  accessToken: e.accessToken,
737
686
  expiresAt: e.expiresAt,
738
687
  sessionId: e.sessionId,
@@ -755,9 +704,8 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
755
704
  *
756
705
  * When `authuser` is provided, the server rotates ONLY that slot
757
706
  * (`oxy_rt_${authuser}`) — sibling accounts on the same device stay
758
- * untouched. When omitted, the server picks the lowest indexed slot
759
- * present (legacy fallback applies). The refresh cookie itself never
760
- * enters JS.
707
+ * untouched. When omitted, the server picks the lowest indexed slot present.
708
+ * The refresh cookie itself never enters JS.
761
709
  *
762
710
  * Returns `null` on 401 (no cookie / expired / reused) so the caller can
763
711
  * fall through cleanly to the unauthenticated path.
@@ -815,9 +763,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
815
763
 
816
764
  /**
817
765
  * Internal: raw `POST /auth/refresh[?authuser=N]` call returning the
818
- * minted access token. Returns `null` on 401 / non-2xx. Used as both the
819
- * implementation of `refreshTokenViaCookie` and the legacy fallback for
820
- * `refreshAllSessions` against older servers.
766
+ * minted access token. Returns `null` on 401 / non-2xx.
821
767
  *
822
768
  * @internal
823
769
  */
@@ -851,11 +797,13 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
851
797
  return null;
852
798
  }
853
799
  const expiresAt = typeof payload.expiresAt === 'string' ? payload.expiresAt : '';
854
- const respAuthuser = typeof payload.authuser === 'number' ? payload.authuser : null;
800
+ if (typeof payload.authuser !== 'number') {
801
+ return null;
802
+ }
855
803
  return {
856
804
  accessToken: payload.accessToken,
857
805
  expiresAt,
858
- authuser: respAuthuser,
806
+ authuser: payload.authuser,
859
807
  };
860
808
  }
861
809
 
@@ -175,7 +175,7 @@ let fedCMActiveController: AbortController | null = null;
175
175
  * - Firefox: Not yet supported (fallback required)
176
176
  *
177
177
  * Key Features:
178
- * - No redirects or popups required
178
+ * - No redirects or secondary windows required
179
179
  * - Browser-native UI prompts
180
180
  * - Privacy-preserving (IdP can't track users)
181
181
  * - Automatic SSO across domains
@@ -245,7 +245,7 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
245
245
  *
246
246
  * This provides a Google-style authentication experience:
247
247
  * - Browser shows native "Sign in with Oxy" prompt
248
- * - No redirect or popup required
248
+ * - No redirect or secondary window required
249
249
  * - User approves → credential exchange happens in browser
250
250
  * - All apps automatically get SSO after first sign-in
251
251
  *
@@ -259,8 +259,8 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
259
259
  * const session = await oxyServices.signInWithFedCM();
260
260
  * console.log('Signed in:', session.user);
261
261
  * } catch (error) {
262
- * // Fallback to popup or redirect auth
263
- * await oxyServices.signInWithPopup();
262
+ * // Fallback to redirect auth
263
+ * oxyServices.signInWithRedirect();
264
264
  * }
265
265
  * ```
266
266
  */
@@ -340,11 +340,10 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
340
340
  // Exchange FedCM ID token for Oxy session
341
341
  const session = await this.exchangeIdTokenForSession(credential.token);
342
342
 
343
- // Store access token in HttpService. `accessToken`/`refreshToken` are
344
- // declared optional on SessionLoginResponse; default the refresh token to
345
- // an empty string when the exchange did not return one.
343
+ // Store the access token in HttpService. Refresh stays in the httpOnly
344
+ // cookie slot set by the API.
346
345
  if (session?.accessToken) {
347
- this.httpService.setTokens(session.accessToken, session.refreshToken ?? '');
346
+ this.httpService.setTokens(session.accessToken);
348
347
  }
349
348
 
350
349
  // Store the user ID as loginHint for future FedCM requests — only now, after
@@ -513,11 +512,10 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
513
512
  return null;
514
513
  }
515
514
 
516
- // Set the access token. `accessToken`/`refreshToken` are declared optional
517
- // on SessionLoginResponse; default the refresh token to an empty string when
518
- // the exchange did not return one.
515
+ // Store the access token. Refresh stays in the httpOnly cookie slot set by
516
+ // the API.
519
517
  if (session.accessToken) {
520
- this.httpService.setTokens(session.accessToken, session.refreshToken ?? '');
518
+ this.httpService.setTokens(session.accessToken);
521
519
  debug.log('Silent SSO: Access token set');
522
520
  } else {
523
521
  debug.warn('Silent SSO: No accessToken in session response');