@oxyhq/core 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,25 @@ export interface PopupAuthOptions {
25
25
  }
26
26
  export interface SilentAuthOptions {
27
27
  timeout?: number;
28
+ /**
29
+ * Override the auth-web (IdP) origin used for the silent iframe, instead of
30
+ * the instance's configured `resolveAuthUrl()`.
31
+ *
32
+ * Why this exists: an instance configured with the CENTRAL IdP
33
+ * (`authWebUrl=https://auth.oxy.so`, for the opaque-code `/sso` bounce and
34
+ * FedCM) cannot read the DURABLE per-apex `fedcm_session` cookie via the
35
+ * central host — that cookie is first-party only on `auth.<rp-apex>` (e.g.
36
+ * `auth.mention.earth`). The cross-domain reload-restore path must point the
37
+ * `/auth/silent` iframe at the PER-APEX host so the cookie is same-site to
38
+ * the RP page (first-party under Safari ITP / Firefox TCP) and the restore
39
+ * is NOT a top-level navigation (no flash, works in a backgrounded tab).
40
+ *
41
+ * When provided this value is used BOTH for the iframe `src` AND for the
42
+ * `postMessage` origin validation in {@link waitForIframeAuth}, so the
43
+ * security check still matches the exact origin the iframe was loaded from.
44
+ * Must be an absolute origin (`https://auth.<apex>`); ignored if empty.
45
+ */
46
+ authWebUrlOverride?: string;
28
47
  }
29
48
  /**
30
49
  * Popup-based Cross-Domain Authentication Mixin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/core",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -31,6 +31,25 @@ export interface PopupAuthOptions {
31
31
 
32
32
  export interface SilentAuthOptions {
33
33
  timeout?: number;
34
+ /**
35
+ * Override the auth-web (IdP) origin used for the silent iframe, instead of
36
+ * the instance's configured `resolveAuthUrl()`.
37
+ *
38
+ * Why this exists: an instance configured with the CENTRAL IdP
39
+ * (`authWebUrl=https://auth.oxy.so`, for the opaque-code `/sso` bounce and
40
+ * FedCM) cannot read the DURABLE per-apex `fedcm_session` cookie via the
41
+ * central host — that cookie is first-party only on `auth.<rp-apex>` (e.g.
42
+ * `auth.mention.earth`). The cross-domain reload-restore path must point the
43
+ * `/auth/silent` iframe at the PER-APEX host so the cookie is same-site to
44
+ * the RP page (first-party under Safari ITP / Firefox TCP) and the restore
45
+ * is NOT a top-level navigation (no flash, works in a backgrounded tab).
46
+ *
47
+ * When provided this value is used BOTH for the iframe `src` AND for the
48
+ * `postMessage` origin validation in {@link waitForIframeAuth}, so the
49
+ * security check still matches the exact origin the iframe was loaded from.
50
+ * Must be an absolute origin (`https://auth.<apex>`); ignored if empty.
51
+ */
52
+ authWebUrlOverride?: string;
34
53
  }
35
54
 
36
55
  /**
@@ -244,6 +263,16 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
244
263
  const nonce = this.generateNonce();
245
264
  const clientId = window.location.origin;
246
265
 
266
+ // Resolve the IdP origin for the iframe. An explicit per-apex override (the
267
+ // durable cross-domain reload path — see `SilentAuthOptions.authWebUrlOverride`)
268
+ // wins over the instance's configured central auth URL. The SAME origin is
269
+ // handed to `waitForIframeAuth` so the postMessage origin check matches the
270
+ // exact host the iframe was loaded from.
271
+ const authOrigin =
272
+ options.authWebUrlOverride && options.authWebUrlOverride.length > 0
273
+ ? options.authWebUrlOverride
274
+ : this.resolveAuthUrl();
275
+
247
276
  const iframe = document.createElement('iframe');
248
277
  iframe.style.display = 'none';
249
278
  iframe.style.position = 'absolute';
@@ -251,13 +280,13 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
251
280
  iframe.style.height = '0';
252
281
  iframe.style.border = 'none';
253
282
 
254
- const silentUrl = `${this.resolveAuthUrl()}/auth/silent?` + `client_id=${encodeURIComponent(clientId)}&` + `nonce=${nonce}`;
283
+ const silentUrl = `${authOrigin}/auth/silent?` + `client_id=${encodeURIComponent(clientId)}&` + `nonce=${nonce}`;
255
284
 
256
285
  iframe.src = silentUrl;
257
286
  document.body.appendChild(iframe);
258
287
 
259
288
  try {
260
- const session = await this.waitForIframeAuth(iframe, timeout, clientId);
289
+ const session = await this.waitForIframeAuth(iframe, timeout, authOrigin);
261
290
 
262
291
  // Bail early on incomplete responses. The iframe contract requires
263
292
  // both an access token and a session id; anything less is unusable.
@@ -475,8 +504,11 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
475
504
  }, timeout);
476
505
 
477
506
  const messageHandler = (event: MessageEvent) => {
478
- // Verify origin
479
- if (event.origin !== this.resolveAuthUrl()) {
507
+ // Verify origin against the EXACT host the iframe was loaded from
508
+ // (`expectedOrigin`). For the per-apex durable-restore path this is
509
+ // `auth.<rp-apex>`, not the instance's central `resolveAuthUrl()` — so
510
+ // we must honour the caller-supplied origin, never re-derive it here.
511
+ if (event.origin !== expectedOrigin) {
480
512
  return;
481
513
  }
482
514