@thunderid/browser 1.11.0 → 1.12.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.
@@ -64,9 +64,10 @@ declare class BackendClient {
64
64
  */
65
65
  refresh(): Promise<boolean>;
66
66
  /**
67
- * The URL that starts sign-in at the backend and comes back to `returnTo`.
67
+ * The URL that starts sign-in at the backend and comes back to `returnTo`. With `ouId`, the backend
68
+ * bounds the sign-in to that organization unit.
68
69
  */
69
- getSignInUrl(returnTo: string): string;
70
+ getSignInUrl(returnTo: string, ouId?: string): string;
70
71
  /**
71
72
  * Ends the backend session.
72
73
  *
@@ -1 +1 @@
1
- {"version":3,"file":"BackendClient.d.ts","sourceRoot":"","sources":["../src/BackendClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,cAAc,EAAE,wBAAwB,EAAE,WAAW,EAAyB,MAAM,uBAAuB,CAAC;AAEpH;;;GAGG;AACH,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAOzD;;;GAGG;AACH,cAAM,aAAa;IAcL,OAAO,CAAC,QAAQ,CAAC,SAAS;IAbtC,OAAO,CAAC,OAAO,CAAsC;IAErD,OAAO,CAAC,UAAU,CAA+B;IAEjD,OAAO,CAAC,gBAAgB,CAAS;IAEjC,0FAA0F;IAC1F,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,SAAS,CAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;gBAE5B,SAAS,EAAE,wBAAwB;IAEhE;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,aAAa,IAAI,IAAI;IAUrB;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAmBtC;;;;;OAKG;IACH,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,IAAI;IA0BtC;;;;;OAKG;IACH,UAAU,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;IAiBnD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,wBAAwB,GAAG,OAAO;IAS1D;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAkB3B;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAItC;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBhC;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkB3C;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMhC;;OAEG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAuBzD;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG;QAC3F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC;YAIa,WAAW;IA4BzB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,IAAI;CAGb;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"BackendClient.d.ts","sourceRoot":"","sources":["../src/BackendClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,cAAc,EAAE,wBAAwB,EAAE,WAAW,EAAyB,MAAM,uBAAuB,CAAC;AAEpH;;;GAGG;AACH,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAOzD;;;GAGG;AACH,cAAM,aAAa;IAcL,OAAO,CAAC,QAAQ,CAAC,SAAS;IAbtC,OAAO,CAAC,OAAO,CAAsC;IAErD,OAAO,CAAC,UAAU,CAA+B;IAEjD,OAAO,CAAC,gBAAgB,CAAS;IAEjC,0FAA0F;IAC1F,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,SAAS,CAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;gBAE5B,SAAS,EAAE,wBAAwB;IAEhE;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,aAAa,IAAI,IAAI;IAUrB;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAmBtC;;;;;OAKG;IACH,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,IAAI;IA0BtC;;;;;OAKG;IACH,UAAU,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;IAiBnD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,wBAAwB,GAAG,OAAO;IAS1D;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAkB3B;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBhC;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkB3C;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMhC;;OAEG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAuBzD;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG;QAC3F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC;YAIa,WAAW;IA4BzB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,IAAI;CAGb;AAED,eAAe,aAAa,CAAC"}
@@ -1,4 +1,4 @@
1
- import { AuthorizeRequestParamValue, ThunderIDJavaScriptClient, User, IsomorphicCrypto, IdToken, OIDCEndpoints, Storage, TokenResponse, HttpRequestConfig, HttpResponse, UserProfile } from '@thunderid/javascript';
1
+ import { AuthorizeRequestParamValue, ThunderIDJavaScriptClient, User, IsomorphicCrypto, IdToken, OIDCEndpoints, Storage, TokenResponse, HttpRequestConfig, HttpResponse, UserProfile, SwitchOrganizationUnitOptions } from '@thunderid/javascript';
2
2
  import FetchHttpClient from './FetchHttpClient';
3
3
  import { BrowserAuthConfig } from './models/BrowserConfig';
4
4
  import SignInConfig from './models/SignInConfig';
@@ -32,6 +32,51 @@ declare class ThunderIDBrowserClient<T = BrowserAuthConfig> extends ThunderIDJav
32
32
  }): Promise<User | undefined>;
33
33
  private _signInInternal;
34
34
  private _exchangeCodeForTokens;
35
+ /**
36
+ * Prepares the sign-out URL and the token refresh for tokens just stored, and reads the user.
37
+ */
38
+ private _startSession;
39
+ /**
40
+ * Signs in again bounded to the organization unit `organizationUnitId`, and replaces the session with
41
+ * the one it gets. The server reuses the SSO session when the user can sign in there, so normally no
42
+ * credentials are asked.
43
+ *
44
+ * - Redirect mode exchanges the session's device secret at `{baseUrl}/ou/{ouId}/oauth2/token` when it
45
+ * holds one, which a sign-in with the `device_sso` scope returns. Otherwise it tries a `prompt=none`
46
+ * request to `{baseUrl}/ou/{ouId}/oauth2/authorize` in a hidden iframe. When the server needs the
47
+ * user, it redirects the page there (unless `redirect` is `false`), and the callback replaces the
48
+ * session.
49
+ * - Embedded mode starts an `AUTHENTICATION` flow with `ouId`, presenting the SSO session handles kept
50
+ * from earlier flow steps. A flow that needs input fails with `interaction_required`; render the
51
+ * sign-in for the unit instead.
52
+ * - Backend mode sends the page to the backend's sign-in endpoint with `ouId`.
53
+ *
54
+ * A failed switch leaves the previous session as it was.
55
+ *
56
+ * @throws {ThunderIDAPIError} With a code from `OrganizationUnitSwitchErrorCodes`.
57
+ */
58
+ switchOrganizationUnit(organizationUnitId: string, options?: SwitchOrganizationUnitOptions): Promise<User | undefined>;
59
+ /**
60
+ * Switches back-channel by exchanging the session's device secret at the unit's token endpoint.
61
+ *
62
+ * @returns The user, `false` when the server needs the user, or `undefined` when the session holds no
63
+ * device secret.
64
+ */
65
+ private _switchOrganizationUnitWithDeviceSecret;
66
+ /**
67
+ * Maps an OAuth error from a bounded sign-in onto the switch's documented errors.
68
+ */
69
+ private static _toSwitchError;
70
+ /**
71
+ * Embedded mode: starts a sign-in flow bounded to the unit. When the SSO session is reused, the flow
72
+ * completes at once and its assertion replaces the session.
73
+ */
74
+ private _switchOrganizationUnitEmbedded;
75
+ /**
76
+ * Completes a switch that left the page for the unit's authorization endpoint: redeems the returned
77
+ * code, or reports the returned error and keeps the previous session.
78
+ */
79
+ private _completeOrganizationUnitSwitch;
35
80
  signInSilently(additionalParams?: Record<string, AuthorizeRequestParamValue>, tokenRequestConfig?: {
36
81
  params: Record<string, unknown>;
37
82
  }): Promise<User | boolean | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDBrowserClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDBrowserClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ThunderIDBrowserClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDBrowserClient.ts"],"names":[],"mappings":"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"}
@@ -162,10 +162,14 @@ var BackendClient = class BackendClient {
162
162
  return this.refreshing;
163
163
  }
164
164
  /**
165
- * The URL that starts sign-in at the backend and comes back to `returnTo`.
165
+ * The URL that starts sign-in at the backend and comes back to `returnTo`. With `ouId`, the backend
166
+ * bounds the sign-in to that organization unit.
166
167
  */
167
- getSignInUrl(returnTo) {
168
- return `${this.endpoints.signIn}?${new URLSearchParams({ returnTo }).toString()}`;
168
+ getSignInUrl(returnTo, ouId) {
169
+ return `${this.endpoints.signIn}?${new URLSearchParams({
170
+ returnTo,
171
+ ...ouId ? { ouId } : {}
172
+ }).toString()}`;
169
173
  }
170
174
  /**
171
175
  * Ends the backend session.
@@ -931,7 +935,7 @@ var AuthenticationHelper = class {
931
935
  * @param timeout - How long to wait for the iframe's response, in milliseconds.
932
936
  * @returns The user session, or `false` if the user is not signed in.
933
937
  */
934
- async signInSilently(constructSilentSignInUrl, requestAccessToken, additionalParams, tokenRequestConfig, timeout = SILENT_SIGN_IN_TIMEOUT) {
938
+ async signInSilently(constructSilentSignInUrl, requestAccessToken, additionalParams, tokenRequestConfig, timeout = SILENT_SIGN_IN_TIMEOUT, onSignedOut) {
935
939
  if (SPAUtils_default.isInitializedSilentSignIn()) {
936
940
  await this.handleSilentSignInResponse();
937
941
  return Promise.resolve({
@@ -966,6 +970,7 @@ var AuthenticationHelper = class {
966
970
  const data = e.data;
967
971
  if (data?.type === SILENT_SIGN_IN_SIGNED_OUT) {
968
972
  cleanUp();
973
+ onSignedOut?.(typeof data?.data?.error === "string" ? data.data.error : void 0);
969
974
  resolve(false);
970
975
  }
971
976
  if (data?.type === SILENT_SIGN_IN_SIGNED_IN && data?.data?.code) {
@@ -996,7 +1001,14 @@ var AuthenticationHelper = class {
996
1001
  state
997
1002
  },
998
1003
  type: SILENT_SIGN_IN_SIGNED_IN
999
- } : { type: SILENT_SIGN_IN_SIGNED_OUT };
1004
+ } : {
1005
+ data: url.searchParams.get("error") ? {
1006
+ code: "",
1007
+ error: url.searchParams.get("error") ?? "",
1008
+ state
1009
+ } : void 0,
1010
+ type: SILENT_SIGN_IN_SIGNED_OUT
1011
+ };
1000
1012
  window.parent.postMessage(message, window.location.origin);
1001
1013
  window.location.href = "about:blank";
1002
1014
  await SPAUtils_default.waitTillPageRedirect();
@@ -2787,6 +2799,24 @@ var SPAHelper_default = SPAHelper;
2787
2799
 
2788
2800
  //#endregion
2789
2801
  //#region src/ThunderIDBrowserClient.ts
2802
+ /**
2803
+ * OAuth errors that mean the server needs the user, so a silent switch falls back to a redirect.
2804
+ */
2805
+ const INTERACTION_ERRORS = [
2806
+ "interaction_required",
2807
+ "login_required",
2808
+ "consent_required",
2809
+ "account_selection_required"
2810
+ ];
2811
+ /**
2812
+ * OAuth errors for a device secret the server cannot use, which the SDK drops before signing in again.
2813
+ */
2814
+ const UNUSABLE_DEVICE_SECRET_ERRORS = ["invalid_request", "invalid_grant"];
2815
+ /**
2816
+ * Temporary-data key that marks a switch to another organization unit left the page, so its callback is
2817
+ * redeemed although the previous session is still signed in.
2818
+ */
2819
+ const ORGANIZATION_UNIT_SWITCH_KEY = "organization_unit_switch";
2790
2820
  const logger$2 = (0, __thunderid_javascript.createPackageComponentLogger)("@thunderid/browser", "ThunderIDBrowserClient");
2791
2821
  const BROWSER_DEFAULT_CONFIG = {
2792
2822
  autoLogoutOnTokenRefreshError: false,
@@ -2920,7 +2950,8 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2920
2950
  await this.isInitialized();
2921
2951
  if (this._backend) {
2922
2952
  if (config?.callOnlyOnRedirect) return;
2923
- location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`);
2953
+ const backendOuId = config?.["organizationUnitId"];
2954
+ location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`, typeof backendOuId === "string" && backendOuId !== "" ? backendOuId : void 0);
2924
2955
  await SPAUtils_default.waitTillPageRedirect();
2925
2956
  return;
2926
2957
  }
@@ -2933,6 +2964,8 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2933
2964
  async _signInInternal(signInConfig, authorizationCode, state, tokenRequestConfig) {
2934
2965
  const sm = this.getStorageManager();
2935
2966
  const config = await sm.getConfigData();
2967
+ const switchedUser = await this._completeOrganizationUnitSwitch(tokenRequestConfig);
2968
+ if (switchedUser) return switchedUser;
2936
2969
  const basicUserInfo = await this._authHelper.handleSignIn();
2937
2970
  if (basicUserInfo) return basicUserInfo;
2938
2971
  let resolvedAuthorizationCode;
@@ -2984,14 +3017,186 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2984
3017
  await this.setPKCECode(pkce, pkceKey);
2985
3018
  }
2986
3019
  await this.requestAccessToken(authorizationCode, state ?? "", void 0, tokenRequestConfig);
3020
+ return this._startSession(config.clientId);
3021
+ }
3022
+ /**
3023
+ * Prepares the sign-out URL and the token refresh for tokens just stored, and reads the user.
3024
+ */
3025
+ async _startSession(clientId) {
2987
3026
  try {
2988
3027
  const signOutUrl = await this.getSignOutUrl();
2989
- SPAUtils_default.setSignOutURL(signOutUrl, config.clientId, this._browserInstanceId);
3028
+ SPAUtils_default.setSignOutURL(signOutUrl, clientId, this._browserInstanceId);
2990
3029
  } catch {}
2991
3030
  await this._spaHelper.clearRefreshTokenTimeout();
2992
3031
  await this._spaHelper.refreshAccessTokenAutomatically(() => this.refreshAccessToken());
2993
3032
  return this.getUser();
2994
3033
  }
3034
+ /**
3035
+ * Signs in again bounded to the organization unit `organizationUnitId`, and replaces the session with
3036
+ * the one it gets. The server reuses the SSO session when the user can sign in there, so normally no
3037
+ * credentials are asked.
3038
+ *
3039
+ * - Redirect mode exchanges the session's device secret at `{baseUrl}/ou/{ouId}/oauth2/token` when it
3040
+ * holds one, which a sign-in with the `device_sso` scope returns. Otherwise it tries a `prompt=none`
3041
+ * request to `{baseUrl}/ou/{ouId}/oauth2/authorize` in a hidden iframe. When the server needs the
3042
+ * user, it redirects the page there (unless `redirect` is `false`), and the callback replaces the
3043
+ * session.
3044
+ * - Embedded mode starts an `AUTHENTICATION` flow with `ouId`, presenting the SSO session handles kept
3045
+ * from earlier flow steps. A flow that needs input fails with `interaction_required`; render the
3046
+ * sign-in for the unit instead.
3047
+ * - Backend mode sends the page to the backend's sign-in endpoint with `ouId`.
3048
+ *
3049
+ * A failed switch leaves the previous session as it was.
3050
+ *
3051
+ * @throws {ThunderIDAPIError} With a code from `OrganizationUnitSwitchErrorCodes`.
3052
+ */
3053
+ async switchOrganizationUnit(organizationUnitId, options = {}) {
3054
+ await this.isInitialized();
3055
+ if (typeof organizationUnitId !== "string" || organizationUnitId.trim() === "") throw new __thunderid_javascript.ThunderIDAPIError("An organization unit identifier is required.", __thunderid_javascript.OrganizationUnitSwitchErrorCodes.InvalidOrganizationUnit, "browser", 400);
3056
+ if (this._backend) {
3057
+ location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`, organizationUnitId);
3058
+ await SPAUtils_default.waitTillPageRedirect();
3059
+ return;
3060
+ }
3061
+ const { redirect = true,...params } = options;
3062
+ const sm = this.getStorageManager();
3063
+ const config = await sm.getConfigData();
3064
+ if (config?.mode === "embedded") return this._switchOrganizationUnitEmbedded(organizationUnitId, config);
3065
+ const exchangedUser = await this._switchOrganizationUnitWithDeviceSecret(organizationUnitId, config);
3066
+ if (exchangedUser) return exchangedUser;
3067
+ let silentError;
3068
+ let silentUser = false;
3069
+ if (exchangedUser === void 0) try {
3070
+ silentUser = await this._authHelper.signInSilently((additional) => this._constructSilentSignInUrl(additional), (code$1, s, trc) => this._exchangeCodeForTokens(code$1, s, trc), {
3071
+ ...params,
3072
+ organizationUnitId
3073
+ }, void 0, config?.session?.silentSignIn?.timeout, (error) => {
3074
+ silentError = error;
3075
+ });
3076
+ } catch (error) {
3077
+ throw ThunderIDBrowserClient._toSwitchError(error instanceof Error ? error.message : void 0, error);
3078
+ }
3079
+ if (silentUser && typeof silentUser === "object") {
3080
+ this._emitHook(Hooks_default.SignIn, silentUser);
3081
+ return silentUser;
3082
+ }
3083
+ if (silentError && !INTERACTION_ERRORS.includes(silentError)) throw ThunderIDBrowserClient._toSwitchError(silentError);
3084
+ if (!redirect) throw ThunderIDBrowserClient._toSwitchError("interaction_required");
3085
+ const url = await this.getSignInUrl({
3086
+ ...params,
3087
+ organizationUnitId
3088
+ });
3089
+ await sm.setTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY, organizationUnitId);
3090
+ location.href = url;
3091
+ await SPAUtils_default.waitTillPageRedirect();
3092
+ }
3093
+ /**
3094
+ * Switches back-channel by exchanging the session's device secret at the unit's token endpoint.
3095
+ *
3096
+ * @returns The user, `false` when the server needs the user, or `undefined` when the session holds no
3097
+ * device secret.
3098
+ */
3099
+ async _switchOrganizationUnitWithDeviceSecret(organizationUnitId, config) {
3100
+ let result;
3101
+ try {
3102
+ result = await this.switchOrganizationUnitWithDeviceSecret(organizationUnitId);
3103
+ } catch (error) {
3104
+ throw ThunderIDBrowserClient._toSwitchError(void 0, error);
3105
+ }
3106
+ if (!result) return;
3107
+ if ("error" in result) {
3108
+ if (INTERACTION_ERRORS.includes(result.error) || UNUSABLE_DEVICE_SECRET_ERRORS.includes(result.error)) return false;
3109
+ throw ThunderIDBrowserClient._toSwitchError(result.error);
3110
+ }
3111
+ const user = await this._startSession(config.clientId ?? "");
3112
+ this._emitHook(Hooks_default.SignIn, user);
3113
+ return user;
3114
+ }
3115
+ /**
3116
+ * Maps an OAuth error from a bounded sign-in onto the switch's documented errors.
3117
+ */
3118
+ static _toSwitchError(oauthError, cause) {
3119
+ if (cause instanceof __thunderid_javascript.ThunderIDAPIError && Object.values(__thunderid_javascript.OrganizationUnitSwitchErrorCodes).includes(cause.code)) return cause;
3120
+ let code$1 = __thunderid_javascript.OrganizationUnitSwitchErrorCodes.Failed;
3121
+ if (oauthError === "unauthorized_client") code$1 = __thunderid_javascript.OrganizationUnitSwitchErrorCodes.UnauthorizedClient;
3122
+ else if (oauthError && INTERACTION_ERRORS.includes(oauthError)) code$1 = __thunderid_javascript.OrganizationUnitSwitchErrorCodes.InteractionRequired;
3123
+ const serverCode = oauthError ?? "switch_failed";
3124
+ return new __thunderid_javascript.ThunderIDAPIError(JSON.stringify({
3125
+ code: serverCode,
3126
+ message: { defaultValue: serverCode }
3127
+ }), code$1, "browser", oauthError === "unauthorized_client" ? 400 : void 0, void 0, "Switching the organization unit failed");
3128
+ }
3129
+ /**
3130
+ * Embedded mode: starts a sign-in flow bounded to the unit. When the SSO session is reused, the flow
3131
+ * completes at once and its assertion replaces the session.
3132
+ */
3133
+ async _switchOrganizationUnitEmbedded(organizationUnitId, config) {
3134
+ let response;
3135
+ const sessionData = await this.getFlowSessions();
3136
+ try {
3137
+ response = await (0, __thunderid_javascript.executeEmbeddedSignInFlow)({
3138
+ baseUrl: config?.baseUrl,
3139
+ payload: {
3140
+ applicationId: config?.applicationId ?? "",
3141
+ flowType: __thunderid_javascript.EmbeddedFlowType.Authentication,
3142
+ ouId: organizationUnitId,
3143
+ ...sessionData.length > 0 ? { sessionData } : {}
3144
+ },
3145
+ url: (0, __thunderid_javascript.resolveResourceEndpoint)("flowExecute", config)
3146
+ });
3147
+ } catch (error) {
3148
+ const serverCode = error instanceof __thunderid_javascript.ThunderIDAPIError ? error.serverError?.code : void 0;
3149
+ throw ThunderIDBrowserClient._toSwitchError(serverCode === "FES-1023" ? "unauthorized_client" : serverCode, error);
3150
+ }
3151
+ await this.storeFlowSessions(response);
3152
+ if (response?.flowStatus === __thunderid_javascript.EmbeddedSignInFlowStatus.Complete && response.assertion) {
3153
+ const claims = await this.decodeJwtToken(response.assertion);
3154
+ const iat = typeof claims["iat"] === "number" ? claims["iat"] : void 0;
3155
+ const exp = typeof claims["exp"] === "number" ? claims["exp"] : void 0;
3156
+ await this.setSession({
3157
+ access_token: response.assertion,
3158
+ created_at: iat ? iat * 1e3 : Date.now(),
3159
+ expires_in: exp && iat ? exp - iat : 3600,
3160
+ id_token: response.assertion,
3161
+ scope: claims["scope"],
3162
+ token_type: "Bearer"
3163
+ });
3164
+ const user = await this.getUser();
3165
+ this._emitHook(Hooks_default.SignIn, user);
3166
+ return user;
3167
+ }
3168
+ if (response?.flowStatus === __thunderid_javascript.EmbeddedSignInFlowStatus.Error) throw ThunderIDBrowserClient._toSwitchError("access_denied");
3169
+ throw ThunderIDBrowserClient._toSwitchError("interaction_required");
3170
+ }
3171
+ /**
3172
+ * Completes a switch that left the page for the unit's authorization endpoint: redeems the returned
3173
+ * code, or reports the returned error and keeps the previous session.
3174
+ */
3175
+ async _completeOrganizationUnitSwitch(tokenRequestConfig) {
3176
+ const sm = this.getStorageManager();
3177
+ if (!await sm.getTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY) || SPAUtils_default.isInitializedSilentSignIn()) return;
3178
+ const url = new URL(window.location.href);
3179
+ const code$1 = url.searchParams.get(__thunderid_javascript.OIDCRequestConstants.Params.AUTHORIZATION_CODE);
3180
+ const state = url.searchParams.get(__thunderid_javascript.OIDCRequestConstants.Params.STATE);
3181
+ const error = url.searchParams.get("error");
3182
+ if (code$1 && state) {
3183
+ await sm.removeTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY);
3184
+ SPAUtils_default.removeAuthorizationCode();
3185
+ try {
3186
+ return await this._exchangeCodeForTokens(code$1, state, tokenRequestConfig);
3187
+ } catch (exchangeError) {
3188
+ throw ThunderIDBrowserClient._toSwitchError(void 0, exchangeError);
3189
+ }
3190
+ }
3191
+ if (error) {
3192
+ await sm.removeTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY);
3193
+ url.searchParams.delete("error");
3194
+ url.searchParams.delete("error_description");
3195
+ url.searchParams.delete(__thunderid_javascript.OIDCRequestConstants.Params.STATE);
3196
+ history.replaceState(null, document.title, url.toString());
3197
+ throw ThunderIDBrowserClient._toSwitchError(error);
3198
+ }
3199
+ }
2995
3200
  async signInSilently(additionalParams, tokenRequestConfig) {
2996
3201
  await this.isInitialized();
2997
3202
  if (this._backend) return await this.isSignedIn() ? this.getUser() : false;
@@ -3288,13 +3493,14 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
3288
3493
  const config = await this.getStorageManager().getConfigData();
3289
3494
  const urlString = await this.getSignInUrl({
3290
3495
  prompt: "none",
3496
+ response_mode: "query",
3291
3497
  state: SILENT_SIGN_IN_STATE,
3292
3498
  ...additionalParams
3293
3499
  });
3294
3500
  const urlObject = new URL(urlString);
3295
- urlObject.searchParams.set("response_mode", "query");
3501
+ if (!urlObject.searchParams.has("request_uri")) urlObject.searchParams.set("response_mode", "query");
3296
3502
  if (this._storage === BrowserStorage_default.BrowserMemory && config.enablePKCE) {
3297
- const state = urlObject.searchParams.get(__thunderid_javascript.OIDCRequestConstants.Params.STATE);
3503
+ const state = urlObject.searchParams.get(__thunderid_javascript.OIDCRequestConstants.Params.STATE) ?? this.lastAuthorizeRequestState;
3298
3504
  SPAUtils_default.setPKCE((0, __thunderid_javascript.extractPkceStorageKeyFromState)(state ?? ""), await this.getPKCECode(state ?? ""));
3299
3505
  }
3300
3506
  return urlObject.toString();
@@ -3379,6 +3585,48 @@ const copyTextToClipboard = async (text) => {
3379
3585
  };
3380
3586
  var copyTextToClipboard_default = copyTextToClipboard;
3381
3587
 
3588
+ //#endregion
3589
+ //#region src/utils/currentProjectStorage.ts
3590
+ /**
3591
+ * The `localStorage` key the current project is kept under, scoped to the vendor like the SDK's
3592
+ * other UI preferences.
3593
+ *
3594
+ * @param vendor - The vendor prefix.
3595
+ * @returns The key.
3596
+ */
3597
+ const getCurrentProjectStorageKey = (vendor) => `${(0, __thunderid_javascript.getVendorPrefix)(vendor)}-current-project`;
3598
+ /**
3599
+ * Reads the project the user last chose. The current project is a client-side preference for the
3600
+ * management UI: it does not change the session, the tokens or what the server allows.
3601
+ *
3602
+ * @param vendor - The vendor prefix.
3603
+ * @returns The project, or `null` when none is kept or storage is unavailable.
3604
+ */
3605
+ const readCurrentProject = (vendor) => {
3606
+ try {
3607
+ if (typeof window === "undefined" || !window.localStorage) return null;
3608
+ const stored = window.localStorage.getItem(getCurrentProjectStorageKey(vendor));
3609
+ const parsed = stored ? JSON.parse(stored) : null;
3610
+ return parsed && typeof parsed === "object" && typeof parsed.id === "string" ? parsed : null;
3611
+ } catch {
3612
+ return null;
3613
+ }
3614
+ };
3615
+ /**
3616
+ * Keeps the project the user chose, or forgets it with `null`.
3617
+ *
3618
+ * @param vendor - The vendor prefix.
3619
+ * @param project - The project, or `null`.
3620
+ */
3621
+ const writeCurrentProject = (vendor, project) => {
3622
+ try {
3623
+ if (typeof window === "undefined" || !window.localStorage) return;
3624
+ const key = getCurrentProjectStorageKey(vendor);
3625
+ if (project) window.localStorage.setItem(key, JSON.stringify(project));
3626
+ else window.localStorage.removeItem(key);
3627
+ } catch {}
3628
+ };
3629
+
3382
3630
  //#endregion
3383
3631
  //#region src/utils/handleWebAuthnAuthentication.ts
3384
3632
  const logger$1 = (0, __thunderid_javascript.createPackageComponentLogger)("@thunderid/browser", "WebAuthn");
@@ -4270,6 +4518,7 @@ exports.detectThemeMode = detectThemeMode;
4270
4518
  exports.extractAvatarParamsFromUri = extractAvatarParamsFromUri_default;
4271
4519
  exports.generateAvatarDataUri = generateAvatarDataUri_default;
4272
4520
  exports.getActiveTheme = getActiveTheme_default;
4521
+ exports.getCurrentProjectStorageKey = getCurrentProjectStorageKey;
4273
4522
  exports.handleWebAuthnAuthentication = handleWebAuthnAuthentication_default;
4274
4523
  exports.hasAuthParamsInUrl = hasAuthParamsInUrl_default;
4275
4524
  exports.hasCalledForThisInstanceInUrl = hasCalledForThisInstanceInUrl_default;
@@ -4279,8 +4528,10 @@ exports.navigate = navigate_default;
4279
4528
  exports.normalizeBorderRadius = normalizeBorderRadius_default;
4280
4529
  exports.pickAnonymousAvatarName = pickAnonymousAvatarName_default;
4281
4530
  exports.pickAnonymousEntityName = pickAnonymousEntityName_default;
4531
+ exports.readCurrentProject = readCurrentProject;
4282
4532
  exports.resolveEmojiUrisInHtml = resolveEmojiUrisInHtml_default;
4283
4533
  exports.resolveLogoUri = resolveLogoUri_default;
4534
+ exports.writeCurrentProject = writeCurrentProject;
4284
4535
  Object.keys(__thunderid_javascript).forEach(function (k) {
4285
4536
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
4286
4537
  enumerable: true,