@oxy.so/core 1.13.0 → 1.16.0

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 (86) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/crypto/webIdentityCarrier.js +1 -1
  3. package/dist/cjs/i18n/locales/ar-SA.json +33 -88
  4. package/dist/cjs/i18n/locales/ca-ES.json +35 -90
  5. package/dist/cjs/i18n/locales/de-DE.json +33 -88
  6. package/dist/cjs/i18n/locales/en-US.json +34 -140
  7. package/dist/cjs/i18n/locales/es-ES.json +33 -139
  8. package/dist/cjs/i18n/locales/fr-FR.json +33 -88
  9. package/dist/cjs/i18n/locales/it-IT.json +33 -88
  10. package/dist/cjs/i18n/locales/ja-JP.json +33 -88
  11. package/dist/cjs/i18n/locales/ko-KR.json +33 -88
  12. package/dist/cjs/i18n/locales/locales/ar-SA.json +33 -88
  13. package/dist/cjs/i18n/locales/locales/ca-ES.json +35 -90
  14. package/dist/cjs/i18n/locales/locales/de-DE.json +33 -88
  15. package/dist/cjs/i18n/locales/locales/en-US.json +34 -140
  16. package/dist/cjs/i18n/locales/locales/es-ES.json +33 -139
  17. package/dist/cjs/i18n/locales/locales/fr-FR.json +33 -88
  18. package/dist/cjs/i18n/locales/locales/it-IT.json +33 -88
  19. package/dist/cjs/i18n/locales/locales/ja-JP.json +33 -88
  20. package/dist/cjs/i18n/locales/locales/ko-KR.json +33 -88
  21. package/dist/cjs/i18n/locales/locales/pt-PT.json +33 -88
  22. package/dist/cjs/i18n/locales/locales/zh-CN.json +34 -89
  23. package/dist/cjs/i18n/locales/pt-PT.json +33 -88
  24. package/dist/cjs/i18n/locales/zh-CN.json +34 -89
  25. package/dist/cjs/index.js +2 -2
  26. package/dist/cjs/server/securityHeaders.js +19 -1
  27. package/dist/cjs/session/accountDialogController.js +37 -142
  28. package/dist/cjs/utils/authWebUrl.js +7 -6
  29. package/dist/cjs/utils/oauthPkce.js +5 -1
  30. package/dist/esm/.tsbuildinfo +1 -1
  31. package/dist/esm/crypto/webIdentityCarrier.js +1 -1
  32. package/dist/esm/i18n/locales/ar-SA.json +33 -88
  33. package/dist/esm/i18n/locales/ca-ES.json +35 -90
  34. package/dist/esm/i18n/locales/de-DE.json +33 -88
  35. package/dist/esm/i18n/locales/en-US.json +34 -140
  36. package/dist/esm/i18n/locales/es-ES.json +33 -139
  37. package/dist/esm/i18n/locales/fr-FR.json +33 -88
  38. package/dist/esm/i18n/locales/it-IT.json +33 -88
  39. package/dist/esm/i18n/locales/ja-JP.json +33 -88
  40. package/dist/esm/i18n/locales/ko-KR.json +33 -88
  41. package/dist/esm/i18n/locales/locales/ar-SA.json +33 -88
  42. package/dist/esm/i18n/locales/locales/ca-ES.json +35 -90
  43. package/dist/esm/i18n/locales/locales/de-DE.json +33 -88
  44. package/dist/esm/i18n/locales/locales/en-US.json +34 -140
  45. package/dist/esm/i18n/locales/locales/es-ES.json +33 -139
  46. package/dist/esm/i18n/locales/locales/fr-FR.json +33 -88
  47. package/dist/esm/i18n/locales/locales/it-IT.json +33 -88
  48. package/dist/esm/i18n/locales/locales/ja-JP.json +33 -88
  49. package/dist/esm/i18n/locales/locales/ko-KR.json +33 -88
  50. package/dist/esm/i18n/locales/locales/pt-PT.json +33 -88
  51. package/dist/esm/i18n/locales/locales/zh-CN.json +34 -89
  52. package/dist/esm/i18n/locales/pt-PT.json +33 -88
  53. package/dist/esm/i18n/locales/zh-CN.json +34 -89
  54. package/dist/esm/index.js +1 -1
  55. package/dist/esm/server/securityHeaders.js +19 -1
  56. package/dist/esm/session/accountDialogController.js +37 -142
  57. package/dist/esm/utils/authWebUrl.js +6 -5
  58. package/dist/esm/utils/oauthPkce.js +5 -1
  59. package/dist/types/.tsbuildinfo +1 -1
  60. package/dist/types/crypto/webIdentityCarrier.d.ts +1 -1
  61. package/dist/types/index.d.ts +3 -3
  62. package/dist/types/server/securityHeaders.d.ts +9 -12
  63. package/dist/types/session/accountDialogController.d.ts +29 -98
  64. package/dist/types/utils/authWebUrl.d.ts +6 -5
  65. package/dist/types/utils/oauthPkce.d.ts +10 -0
  66. package/package.json +2 -2
  67. package/src/crypto/webIdentityCarrier.ts +1 -1
  68. package/src/i18n/locales/ar-SA.json +33 -88
  69. package/src/i18n/locales/ca-ES.json +35 -90
  70. package/src/i18n/locales/de-DE.json +33 -88
  71. package/src/i18n/locales/en-US.json +34 -140
  72. package/src/i18n/locales/es-ES.json +33 -139
  73. package/src/i18n/locales/fr-FR.json +33 -88
  74. package/src/i18n/locales/it-IT.json +33 -88
  75. package/src/i18n/locales/ja-JP.json +33 -88
  76. package/src/i18n/locales/ko-KR.json +33 -88
  77. package/src/i18n/locales/pt-PT.json +33 -88
  78. package/src/i18n/locales/zh-CN.json +34 -89
  79. package/src/index.ts +2 -3
  80. package/src/server/__tests__/securityHeaders.test.ts +17 -0
  81. package/src/server/securityHeaders.ts +29 -1
  82. package/src/session/__tests__/accountDialogController.test.ts +42 -184
  83. package/src/session/accountDialogController.ts +50 -185
  84. package/src/utils/__tests__/oauthPkce.test.ts +7 -0
  85. package/src/utils/authWebUrl.ts +6 -5
  86. package/src/utils/oauthPkce.ts +16 -1
@@ -37,12 +37,6 @@
37
37
  * - `commonsAvailability` — whether Commons is installed on this device
38
38
  * (native only, via the injected `canOpenApp` probe), so the QR view can
39
39
  * offer a "Get Commons" fallback instead of a same-device dead end.
40
- * - `startPasskeyHubSignIn` — on a non-Oxy web origin (where a WebAuthn
41
- * ceremony can't run locally, the RP-ID is bound to oxy.so), open a popup
42
- * at the auth.oxy.so passkey hub instead, scoped to the SAME device-flow
43
- * session `showQr` creates, and complete it via the SAME poll/socket/claim
44
- * engine. Falls back to `showQr`'s plain QR rendering if the popup is
45
- * blocked.
46
40
  *
47
41
  * Sign-in is passkey (WebAuthn) or the Commons QR / shared-keychain handoff —
48
42
  * password, social login, and 2FA were removed ecosystem-wide. Account
@@ -62,7 +56,6 @@ exports.backViewOf = backViewOf;
62
56
  exports.createAccountDialogController = createAccountDialogController;
63
57
  const logger_1 = require("../logger");
64
58
  const errorUtils_1 = require("../utils/errorUtils");
65
- const authWebUrl_1 = require("../utils/authWebUrl");
66
59
  const socketLoader_1 = require("./socketLoader");
67
60
  const deviceDirectory_1 = require("./deviceDirectory");
68
61
  const commonsDelivery_1 = require("../utils/commonsDelivery");
@@ -130,8 +123,8 @@ const IDLE_SIGN_IN_FACTS = {
130
123
  */
131
124
  const COMPLETED_SIGN_IN_FACTS = { ...IDLE_SIGN_IN_FACTS, phase: 'completed' };
132
125
  /** The full flow state for `facts`, stamped with the attempt it belongs to. */
133
- function buildSignIn(facts, attempt) {
134
- return { ...facts, progress: deriveSignInProgress(facts), attempt };
126
+ function buildSignIn(facts, attempt, inline) {
127
+ return { ...facts, progress: deriveSignInProgress(facts), attempt, inline };
135
128
  }
136
129
  function errorMessage(error) {
137
130
  return error instanceof Error ? error.message : String(error);
@@ -163,7 +156,7 @@ class AccountDialogController {
163
156
  * alongside the three flags above.
164
157
  */
165
158
  this.exclusiveMutationInFlight = false;
166
- this.signIn = buildSignIn(IDLE_SIGN_IN_FACTS, 0);
159
+ this.signIn = buildSignIn(IDLE_SIGN_IN_FACTS, 0, false);
167
160
  this.commonsAvailability = 'unknown';
168
161
  // --- Sign-in device-flow bookkeeping ---
169
162
  /**
@@ -192,10 +185,6 @@ class AccountDialogController {
192
185
  * ABANDONED request never blocks the next request's first poll.
193
186
  */
194
187
  this.pollInFlightToken = null;
195
- /** The popup opened by {@link startPasskeyHubSignIn}, or `null`. */
196
- this.activePopup = null;
197
- /** Watches {@link activePopup}'s `closed` state; see {@link watchPopup}. */
198
- this.popupWatchTimer = null;
199
188
  // --- Store plumbing ---
200
189
  this.unsubscribeSession = null;
201
190
  this.unsubscribeTokens = null;
@@ -212,8 +201,6 @@ class AccountDialogController {
212
201
  this.openUrl = options.openUrl;
213
202
  this.canOpenApp = options.canOpenApp;
214
203
  this.socketFactory = options.socketFactory;
215
- this.openPopup = options.openPopup;
216
- this.identityOrigin = options.identityOrigin ?? options.hubBaseUrl ?? authWebUrl_1.IDENTITY_WEB_ORIGIN;
217
204
  this.platform = options.platform ?? 'unknown';
218
205
  this.snapshot = this.computeSnapshot();
219
206
  }
@@ -291,7 +278,6 @@ class AccountDialogController {
291
278
  }
292
279
  this.clearPollTimer();
293
280
  this.closeAuthSessionSocket();
294
- this.closeActivePopup();
295
281
  this.signInToken = null;
296
282
  this.listeners.clear();
297
283
  }
@@ -356,12 +342,12 @@ class AccountDialogController {
356
342
  if (this.view === view)
357
343
  return;
358
344
  this.view = view;
359
- // A `'completed'` flow owns no timers, socket, popup, or token — it is only
345
+ // A `'completed'` flow owns no timers, socket, or token — it is only
360
346
  // the terminal "Identity confirmed" the finished surface showed. Moving to
361
347
  // another view is a NEW intention, so drop it; otherwise a later `add()`
362
348
  // would open on the previous sign-in's terminal state.
363
349
  if (this.signIn.phase === 'completed') {
364
- this.signIn = buildSignIn(IDLE_SIGN_IN_FACTS, this.signInAttempt);
350
+ this.signIn = this.stampSignIn(IDLE_SIGN_IN_FACTS);
365
351
  }
366
352
  this.emit();
367
353
  }
@@ -678,82 +664,33 @@ class AccountDialogController {
678
664
  await this.startDeviceFlowSession(attempt, { deliver: true });
679
665
  }
680
666
  /**
681
- * Start a NEW attempt the same way the last one was started — "Try again"
682
- * repeats the user's choice rather than silently switching method. A failed
683
- * passkey-hub attempt reopens the hub popup; a failed "Sign in with Oxy"
684
- * retries that; an explicit QR request shows the QR.
667
+ * The sign-in entry's EMBEDDED QR: a request whose only route is the QR,
668
+ * started without leaving the current view.
685
669
  *
686
- * Call it straight from the press handler: the hub route opens its popup
687
- * synchronously, before this method's first `await`, so the browser still
688
- * attributes it to the click.
670
+ * Unlike {@link showQr} it runs no delivery selection. The surface starts it
671
+ * by itself, on mount, so it must not push to the person's phone or open
672
+ * Commons — nobody asked for either. Any other sign-in the person then
673
+ * chooses supersedes it (and withdraws its request) like any new attempt.
674
+ */
675
+ async startInlineQr() {
676
+ const attempt = this.beginSignInAttempt('inline-qr');
677
+ await this.startDeviceFlowSession(attempt, { deliver: false });
678
+ }
679
+ /**
680
+ * Start a NEW attempt the same way the last one was started — "Try again"
681
+ * repeats the user's choice rather than silently switching method: a failed
682
+ * "Sign in with Oxy" retries that; an explicit QR request shows the QR.
689
683
  */
690
684
  retrySignIn() {
691
685
  switch (this.signInMethod) {
692
- case 'passkey-hub':
693
- return this.startPasskeyHubSignIn();
694
686
  case 'qr':
695
687
  return this.showQr();
688
+ case 'inline-qr':
689
+ return this.startInlineQr();
696
690
  default:
697
691
  return this.signInWithOxy();
698
692
  }
699
693
  }
700
- /**
701
- * Web-only: sign in (or create an account) with a passkey at the web identity
702
- * carrier. The ceremony runs on `id.oxy.so`, never on the calling origin, for
703
- * two reasons: a credential minted with `WEBAUTHN_RP_ID=oxy.so` can only be
704
- * asserted from `oxy.so`/a subdomain/loopback (a browser-enforced boundary),
705
- * and only the identity origin may unseal or create the account's identity
706
- * (one identity, two carriers). Opens a popup at `<identityOrigin>/continue`,
707
- * scoped to the SAME device-flow
708
- * session {@link showQr} would create (same `authorizeCode`/`sessionToken`
709
- * pair), and let the SAME poll/socket/claim engine complete it once the hub
710
- * authorizes the session (`POST /auth/session/authorize-code/:authorizeCode`,
711
- * bearer-authed, server-side — this method never sees or transmits the
712
- * secret `sessionToken`).
713
- *
714
- * The popup MUST be opened synchronously, before any `await`, or the
715
- * browser's popup blocker loses the click-gesture attribution and silently
716
- * blocks it — so {@link openPopup} is invoked as the very first step, before
717
- * the device-flow session (which needs an async call) even exists. If the
718
- * popup is blocked (or no `openPopup` was injected), this falls back to
719
- * `showQr`'s plain QR rendering — no dead end.
720
- */
721
- async startPasskeyHubSignIn() {
722
- const attempt = this.beginSignInAttempt('passkey-hub');
723
- this.setView('qr');
724
- const popup = this.openPopup?.() ?? null;
725
- if (!popup) {
726
- await this.startDeviceFlowSession(attempt, { deliver: true });
727
- return;
728
- }
729
- // Owned by the attempt from the moment it exists, so cancelling while the
730
- // session is still being created closes it instead of leaving a blank
731
- // window behind.
732
- this.activePopup = popup;
733
- // The hub popup IS the primary surface here, chosen explicitly by the user —
734
- // so this flow does NOT run automatic Commons delivery (ringing the user's
735
- // phone because they asked for a passkey would be exactly the "menu of
736
- // methods" the one-primary-action rule forbids). The underlying request is
737
- // the same `AuthSession`, and its Commons route stays the QR the view
738
- // renders beneath the popup.
739
- const handle = await this.startDeviceFlowSession(attempt, { deliver: false });
740
- // `null` means the attempt failed (its teardown closed the popup) or was
741
- // abandoned (the cancel closed it).
742
- if (!handle)
743
- return;
744
- // The user may have closed the popup during the async session creation
745
- // above, before any watcher was attached to catch it — guard rather than
746
- // navigate a dead window (browsers vary on whether that throws).
747
- if (popup.closed) {
748
- const pendingCode = this.signIn.authorizeCode;
749
- this.failSignIn('cancelled', 'Sign-in was cancelled.');
750
- if (pendingCode)
751
- void this.withdrawRequest(pendingCode);
752
- return;
753
- }
754
- popup.location.href = `${this.identityOrigin}/continue?code=${encodeURIComponent(handle.authorizeCode)}`;
755
- this.watchPopup(popup);
756
- }
757
694
  /**
758
695
  * End whatever attempt is running (withdrawing its request) and begin a new
759
696
  * one. Returns the new attempt's identity for the caller to re-check after
@@ -769,9 +706,9 @@ class AccountDialogController {
769
706
  return attempt === this.signInAttempt;
770
707
  }
771
708
  /**
772
- * Shared device-flow session creation for both {@link showQr} (renders the
773
- * QR) and {@link startPasskeyHubSignIn} (also opens the hub popup) — the
774
- * same `startCommonsSignIn` → poll/socket wiring either way. Returns the
709
+ * Shared device-flow session creation for {@link signInWithOxy},
710
+ * {@link showQr} and {@link startInlineQr} — the same `startCommonsSignIn` →
711
+ * poll/socket wiring every time. Returns the
775
712
  * handle on success (already reflected in `signIn`), or `null` when the
776
713
  * attempt failed (already set as `signIn.failure`) or was abandoned while the
777
714
  * request was being created.
@@ -782,8 +719,8 @@ class AccountDialogController {
782
719
  * request, a socket, and a poll behind it.
783
720
  * @param opts.deliver - Whether to run automatic Commons delivery selection
784
721
  * ({@link resolveDeliveryRoute}). `true` for the normal one-primary-action
785
- * entry; `false` when the caller already owns the primary surface (the
786
- * passkey hub popup), where the request's Commons route is simply the QR.
722
+ * entry; `false` for the embedded QR, which the screen starts by itself,
723
+ * where the request's Commons route is simply the QR.
787
724
  */
788
725
  async startDeviceFlowSession(attempt, opts) {
789
726
  if (!this.isCurrentAttempt(attempt))
@@ -826,9 +763,9 @@ class AccountDialogController {
826
763
  void this.openAuthSessionSocket(handle.sessionToken);
827
764
  this.scheduleNextPoll(handle.sessionToken);
828
765
  if (opts.deliver) {
829
- // Non-blocking on purpose: the QR/authorizeCode are already renderable
830
- // and the popup caller can navigate immediately, while the route (a
831
- // local probe plus at most one delivery round-trip) resolves behind it.
766
+ // Non-blocking on purpose: the QR/authorizeCode are already renderable,
767
+ // while the route (a local probe plus at most one delivery round-trip)
768
+ // resolves behind it.
832
769
  void this.resolveDeliveryRoute(handle);
833
770
  }
834
771
  return handle;
@@ -932,49 +869,6 @@ class AccountDialogController {
932
869
  return false;
933
870
  }
934
871
  }
935
- /**
936
- * Poll {@link PopupWindowHandle.closed} so a user who dismisses the hub
937
- * popup without completing sign-in gets prompt feedback (there is no DOM
938
- * event for a cross-origin popup closing — polling is the only mechanism).
939
- * Cleared by {@link closeActivePopup}, which every sign-in exit path already
940
- * calls.
941
- */
942
- watchPopup(popup) {
943
- this.clearPopupWatchTimer();
944
- this.popupWatchTimer = setInterval(() => {
945
- if (!popup.closed)
946
- return;
947
- this.clearPopupWatchTimer();
948
- if (this.signIn.phase === 'starting' || this.signIn.phase === 'waiting') {
949
- // Closing the surface cancels the REQUEST too, not just this listener.
950
- const pendingCode = this.signIn.authorizeCode;
951
- this.failSignIn('cancelled', 'Sign-in was cancelled.');
952
- if (pendingCode) {
953
- void this.withdrawRequest(pendingCode);
954
- }
955
- }
956
- }, 1000);
957
- }
958
- clearPopupWatchTimer() {
959
- if (this.popupWatchTimer !== null) {
960
- clearInterval(this.popupWatchTimer);
961
- this.popupWatchTimer = null;
962
- }
963
- }
964
- /** Tear down the popup watch timer and close the popup, if any. Idempotent. */
965
- closeActivePopup() {
966
- this.clearPopupWatchTimer();
967
- const popup = this.activePopup;
968
- this.activePopup = null;
969
- if (!popup || popup.closed)
970
- return;
971
- try {
972
- popup.close();
973
- }
974
- catch (error) {
975
- logger_1.logger.debug('[AccountDialogController] popup close failed', { component: 'AccountDialogController' }, error);
976
- }
977
- }
978
872
  /**
979
873
  * Resolve whether Commons is installed on this device via the injected
980
874
  * `canOpenApp` probe, updating {@link commonsAvailability} as durable,
@@ -1004,7 +898,7 @@ class AccountDialogController {
1004
898
  this.emit();
1005
899
  }
1006
900
  /**
1007
- * Tear down the active sign-in device flow (timers + socket + popup + token),
901
+ * Tear down the active sign-in device flow (timers + socket + token),
1008
902
  * WITHDRAW the request server-side, and reset to idle.
1009
903
  *
1010
904
  * Cancellation has to converge in both directions: the surface closing must
@@ -1027,7 +921,6 @@ class AccountDialogController {
1027
921
  : null;
1028
922
  this.clearPollTimer();
1029
923
  this.closeAuthSessionSocket();
1030
- this.closeActivePopup();
1031
924
  this.signInToken = null;
1032
925
  if (this.signIn.phase !== 'idle') {
1033
926
  this.setSignIn(IDLE_SIGN_IN_FACTS);
@@ -1226,10 +1119,9 @@ class AccountDialogController {
1226
1119
  this.signInToken = null;
1227
1120
  this.clearPollTimer();
1228
1121
  this.closeAuthSessionSocket();
1229
- this.closeActivePopup();
1230
1122
  // Terminal SUCCESS, not idle: the surface gets one honest frame to show
1231
1123
  // "Identity confirmed" before it closes. Cleared on the next view change.
1232
- this.signIn = buildSignIn(COMPLETED_SIGN_IN_FACTS, this.signInAttempt);
1124
+ this.signIn = this.stampSignIn(COMPLETED_SIGN_IN_FACTS);
1233
1125
  this.view = 'accounts';
1234
1126
  this.emit();
1235
1127
  }
@@ -1256,7 +1148,6 @@ class AccountDialogController {
1256
1148
  failSignIn(failure, message) {
1257
1149
  this.clearPollTimer();
1258
1150
  this.closeAuthSessionSocket();
1259
- this.closeActivePopup();
1260
1151
  this.signInToken = null;
1261
1152
  this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'error', error: message, failure });
1262
1153
  }
@@ -1348,9 +1239,13 @@ class AccountDialogController {
1348
1239
  * to advance without a fact behind it.
1349
1240
  */
1350
1241
  setSignIn(facts) {
1351
- this.signIn = buildSignIn(facts, this.signInAttempt);
1242
+ this.signIn = this.stampSignIn(facts);
1352
1243
  this.emit();
1353
1244
  }
1245
+ /** `facts` as the current attempt's state. */
1246
+ stampSignIn(facts) {
1247
+ return buildSignIn(facts, this.signInAttempt, this.signInMethod === 'inline-qr');
1248
+ }
1354
1249
  /** Update a subset of the device-flow facts, re-deriving `progress`. */
1355
1250
  patchSignIn(patch) {
1356
1251
  const { phase, authorizeCode, qrPayload, expiresAt, error, failure, route, routeFailed, pushSentAt, openedAt, } = this.signIn;
@@ -10,7 +10,7 @@
10
10
  * past the SSO/FedCM teardown.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.IDENTITY_WEB_ORIGIN = exports.CENTRAL_IDP_APEX = void 0;
13
+ exports.AUTH_WEB_ORIGIN = exports.CENTRAL_IDP_APEX = void 0;
14
14
  /**
15
15
  * The registrable apex (eTLD+1) of the Oxy ecosystem's central Identity
16
16
  * Provider, reachable at `auth.${CENTRAL_IDP_APEX}`. Single source of truth so
@@ -18,9 +18,10 @@ exports.IDENTITY_WEB_ORIGIN = exports.CENTRAL_IDP_APEX = void 0;
18
18
  */
19
19
  exports.CENTRAL_IDP_APEX = 'oxy.so';
20
20
  /**
21
- * The web identity carrier's origin — where a person signs in or creates an
22
- * account with a passkey, and where their self-custody identity is kept sealed
23
- * under that passkey (one identity, two carriers). Apps open it; they never
24
- * handle the identity themselves.
21
+ * The IdP's origin, `auth.oxy.so` — the OAuth authorize/consent surface AND the
22
+ * web identity carrier: where a person signs in or creates an account with a
23
+ * passkey from another origin's popup, and the one origin that may create,
24
+ * open, recover or move their self-custody identity (one identity, two
25
+ * carriers). Apps open it; they never handle the identity themselves.
25
26
  */
26
- exports.IDENTITY_WEB_ORIGIN = `https://id.${exports.CENTRAL_IDP_APEX}`;
27
+ exports.AUTH_WEB_ORIGIN = `https://auth.${exports.CENTRAL_IDP_APEX}`;
@@ -29,10 +29,11 @@ exports.consumeOAuthReturnPath = consumeOAuthReturnPath;
29
29
  exports.persistOAuthHandshake = persistOAuthHandshake;
30
30
  exports.readOAuthHandshake = readOAuthHandshake;
31
31
  exports.clearOAuthHandshake = clearOAuthHandshake;
32
+ const authWebUrl_1 = require("./authWebUrl");
32
33
  const protocol_1 = require("@oxy.so/protocol");
33
34
  const logger_1 = require("../logger");
34
35
  /** The central Oxy IdP authorization endpoint used by default. */
35
- exports.OXY_AUTHORIZE_URL = 'https://auth.oxy.so/authorize';
36
+ exports.OXY_AUTHORIZE_URL = `${authWebUrl_1.AUTH_WEB_ORIGIN}/authorize`;
36
37
  /** Default OAuth scope requested for a "Sign in with Oxy" third-party flow. */
37
38
  exports.DEFAULT_OAUTH_SCOPE = 'openid profile';
38
39
  /**
@@ -151,6 +152,9 @@ function buildOAuthAuthorizeUrl(params) {
151
152
  if (params.responseMode) {
152
153
  url.searchParams.set('response_mode', params.responseMode);
153
154
  }
155
+ if (params.screen) {
156
+ url.searchParams.set('screen', params.screen);
157
+ }
154
158
  return url.toString();
155
159
  }
156
160
  /** `sessionStorage` key for the OAuth CSRF `state` across an authorize redirect. */