@thunderid/browser 1.10.0 → 1.12.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.
- package/dist/BackendClient.d.ts +3 -2
- package/dist/BackendClient.d.ts.map +1 -1
- package/dist/ThunderIDBrowserClient.d.ts +46 -1
- package/dist/ThunderIDBrowserClient.d.ts.map +1 -1
- package/dist/cjs/index.cjs +260 -9
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +259 -11
- package/dist/index.js.map +1 -1
- package/dist/utils/AuthenticationHelper.d.ts +1 -1
- package/dist/utils/AuthenticationHelper.d.ts.map +1 -1
- package/dist/utils/currentProjectStorage.d.ts +25 -0
- package/dist/utils/currentProjectStorage.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export { default as navigate } from './utils/navigate';
|
|
|
26
26
|
export { default as http } from './utils/http';
|
|
27
27
|
export { default as createHttpClientFetcher } from './utils/createHttpClientFetcher';
|
|
28
28
|
export { default as copyTextToClipboard } from './utils/copyTextToClipboard';
|
|
29
|
+
export { getCurrentProjectStorageKey, readCurrentProject, writeCurrentProject } from './utils/currentProjectStorage';
|
|
29
30
|
export { default as handleWebAuthnAuthentication } from './utils/handleWebAuthnAuthentication';
|
|
30
31
|
export { default as resolveEmojiUrisInHtml } from './utils/resolveEmojiUrisInHtml';
|
|
31
32
|
export { default as isAvatarUri, AVATAR_URI_SCHEME } from './utils/isAvatarUri';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'buffer/index.js';
|
|
2
2
|
if (typeof window !== 'undefined' && !window.Buffer) { window.Buffer = Buffer; }
|
|
3
|
-
import { DEFAULT_THEME, HttpClient, OIDCRequestConstants, ThunderIDAuthException, ThunderIDJavaScriptClient, ThunderIDRuntimeError, TokenConstants, arrayBufferToBase64url, base64urlToArrayBuffer, createPackageComponentLogger, extractEmojiFromUri, extractPkceStorageKeyFromState, generateFlattenedUserProfile, getTokenPermissions, getUsersMe, isEmojiUri, resolveBackendEndpoints, resolveRequestBaseUrl, resolveResourceEndpoint } from "@thunderid/javascript";
|
|
3
|
+
import { DEFAULT_THEME, EmbeddedFlowType, EmbeddedSignInFlowStatus, HttpClient, OIDCRequestConstants, OrganizationUnitSwitchErrorCodes, ThunderIDAPIError, ThunderIDAuthException, ThunderIDJavaScriptClient, ThunderIDRuntimeError, TokenConstants, arrayBufferToBase64url, base64urlToArrayBuffer, createPackageComponentLogger, executeEmbeddedSignInFlow, extractEmojiFromUri, extractPkceStorageKeyFromState, generateFlattenedUserProfile, getTokenPermissions, getUsersMe, getVendorPrefix, isEmojiUri, resolveBackendEndpoints, resolveRequestBaseUrl, resolveResourceEndpoint } from "@thunderid/javascript";
|
|
4
4
|
import base64url from "base64url";
|
|
5
5
|
import sha256 from "fast-sha256";
|
|
6
6
|
import { createLocalJWKSet, jwtVerify } from "jose";
|
|
@@ -160,10 +160,14 @@ var BackendClient = class BackendClient {
|
|
|
160
160
|
return this.refreshing;
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
|
-
* The URL that starts sign-in at the backend and comes back to `returnTo`.
|
|
163
|
+
* The URL that starts sign-in at the backend and comes back to `returnTo`. With `ouId`, the backend
|
|
164
|
+
* bounds the sign-in to that organization unit.
|
|
164
165
|
*/
|
|
165
|
-
getSignInUrl(returnTo) {
|
|
166
|
-
return `${this.endpoints.signIn}?${new URLSearchParams({
|
|
166
|
+
getSignInUrl(returnTo, ouId) {
|
|
167
|
+
return `${this.endpoints.signIn}?${new URLSearchParams({
|
|
168
|
+
returnTo,
|
|
169
|
+
...ouId ? { ouId } : {}
|
|
170
|
+
}).toString()}`;
|
|
167
171
|
}
|
|
168
172
|
/**
|
|
169
173
|
* Ends the backend session.
|
|
@@ -929,7 +933,7 @@ var AuthenticationHelper = class {
|
|
|
929
933
|
* @param timeout - How long to wait for the iframe's response, in milliseconds.
|
|
930
934
|
* @returns The user session, or `false` if the user is not signed in.
|
|
931
935
|
*/
|
|
932
|
-
async signInSilently(constructSilentSignInUrl, requestAccessToken, additionalParams, tokenRequestConfig, timeout = SILENT_SIGN_IN_TIMEOUT) {
|
|
936
|
+
async signInSilently(constructSilentSignInUrl, requestAccessToken, additionalParams, tokenRequestConfig, timeout = SILENT_SIGN_IN_TIMEOUT, onSignedOut) {
|
|
933
937
|
if (SPAUtils_default.isInitializedSilentSignIn()) {
|
|
934
938
|
await this.handleSilentSignInResponse();
|
|
935
939
|
return Promise.resolve({
|
|
@@ -964,6 +968,7 @@ var AuthenticationHelper = class {
|
|
|
964
968
|
const data = e.data;
|
|
965
969
|
if (data?.type === SILENT_SIGN_IN_SIGNED_OUT) {
|
|
966
970
|
cleanUp();
|
|
971
|
+
onSignedOut?.(typeof data?.data?.error === "string" ? data.data.error : void 0);
|
|
967
972
|
resolve(false);
|
|
968
973
|
}
|
|
969
974
|
if (data?.type === SILENT_SIGN_IN_SIGNED_IN && data?.data?.code) {
|
|
@@ -994,7 +999,14 @@ var AuthenticationHelper = class {
|
|
|
994
999
|
state
|
|
995
1000
|
},
|
|
996
1001
|
type: SILENT_SIGN_IN_SIGNED_IN
|
|
997
|
-
} : {
|
|
1002
|
+
} : {
|
|
1003
|
+
data: url.searchParams.get("error") ? {
|
|
1004
|
+
code: "",
|
|
1005
|
+
error: url.searchParams.get("error") ?? "",
|
|
1006
|
+
state
|
|
1007
|
+
} : void 0,
|
|
1008
|
+
type: SILENT_SIGN_IN_SIGNED_OUT
|
|
1009
|
+
};
|
|
998
1010
|
window.parent.postMessage(message, window.location.origin);
|
|
999
1011
|
window.location.href = "about:blank";
|
|
1000
1012
|
await SPAUtils_default.waitTillPageRedirect();
|
|
@@ -2785,6 +2797,24 @@ var SPAHelper_default = SPAHelper;
|
|
|
2785
2797
|
|
|
2786
2798
|
//#endregion
|
|
2787
2799
|
//#region src/ThunderIDBrowserClient.ts
|
|
2800
|
+
/**
|
|
2801
|
+
* OAuth errors that mean the server needs the user, so a silent switch falls back to a redirect.
|
|
2802
|
+
*/
|
|
2803
|
+
const INTERACTION_ERRORS = [
|
|
2804
|
+
"interaction_required",
|
|
2805
|
+
"login_required",
|
|
2806
|
+
"consent_required",
|
|
2807
|
+
"account_selection_required"
|
|
2808
|
+
];
|
|
2809
|
+
/**
|
|
2810
|
+
* OAuth errors for a device secret the server cannot use, which the SDK drops before signing in again.
|
|
2811
|
+
*/
|
|
2812
|
+
const UNUSABLE_DEVICE_SECRET_ERRORS = ["invalid_request", "invalid_grant"];
|
|
2813
|
+
/**
|
|
2814
|
+
* Temporary-data key that marks a switch to another organization unit left the page, so its callback is
|
|
2815
|
+
* redeemed although the previous session is still signed in.
|
|
2816
|
+
*/
|
|
2817
|
+
const ORGANIZATION_UNIT_SWITCH_KEY = "organization_unit_switch";
|
|
2788
2818
|
const logger$2 = createPackageComponentLogger("@thunderid/browser", "ThunderIDBrowserClient");
|
|
2789
2819
|
const BROWSER_DEFAULT_CONFIG = {
|
|
2790
2820
|
autoLogoutOnTokenRefreshError: false,
|
|
@@ -2918,7 +2948,8 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2918
2948
|
await this.isInitialized();
|
|
2919
2949
|
if (this._backend) {
|
|
2920
2950
|
if (config?.callOnlyOnRedirect) return;
|
|
2921
|
-
|
|
2951
|
+
const backendOuId = config?.["organizationUnitId"];
|
|
2952
|
+
location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`, typeof backendOuId === "string" && backendOuId !== "" ? backendOuId : void 0);
|
|
2922
2953
|
await SPAUtils_default.waitTillPageRedirect();
|
|
2923
2954
|
return;
|
|
2924
2955
|
}
|
|
@@ -2931,6 +2962,8 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2931
2962
|
async _signInInternal(signInConfig, authorizationCode, state, tokenRequestConfig) {
|
|
2932
2963
|
const sm = this.getStorageManager();
|
|
2933
2964
|
const config = await sm.getConfigData();
|
|
2965
|
+
const switchedUser = await this._completeOrganizationUnitSwitch(tokenRequestConfig);
|
|
2966
|
+
if (switchedUser) return switchedUser;
|
|
2934
2967
|
const basicUserInfo = await this._authHelper.handleSignIn();
|
|
2935
2968
|
if (basicUserInfo) return basicUserInfo;
|
|
2936
2969
|
let resolvedAuthorizationCode;
|
|
@@ -2982,14 +3015,186 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2982
3015
|
await this.setPKCECode(pkce, pkceKey);
|
|
2983
3016
|
}
|
|
2984
3017
|
await this.requestAccessToken(authorizationCode, state ?? "", void 0, tokenRequestConfig);
|
|
3018
|
+
return this._startSession(config.clientId);
|
|
3019
|
+
}
|
|
3020
|
+
/**
|
|
3021
|
+
* Prepares the sign-out URL and the token refresh for tokens just stored, and reads the user.
|
|
3022
|
+
*/
|
|
3023
|
+
async _startSession(clientId) {
|
|
2985
3024
|
try {
|
|
2986
3025
|
const signOutUrl = await this.getSignOutUrl();
|
|
2987
|
-
SPAUtils_default.setSignOutURL(signOutUrl,
|
|
3026
|
+
SPAUtils_default.setSignOutURL(signOutUrl, clientId, this._browserInstanceId);
|
|
2988
3027
|
} catch {}
|
|
2989
3028
|
await this._spaHelper.clearRefreshTokenTimeout();
|
|
2990
3029
|
await this._spaHelper.refreshAccessTokenAutomatically(() => this.refreshAccessToken());
|
|
2991
3030
|
return this.getUser();
|
|
2992
3031
|
}
|
|
3032
|
+
/**
|
|
3033
|
+
* Signs in again bounded to the organization unit `organizationUnitId`, and replaces the session with
|
|
3034
|
+
* the one it gets. The server reuses the SSO session when the user can sign in there, so normally no
|
|
3035
|
+
* credentials are asked.
|
|
3036
|
+
*
|
|
3037
|
+
* - Redirect mode exchanges the session's device secret at `{baseUrl}/ou/{ouId}/oauth2/token` when it
|
|
3038
|
+
* holds one, which a sign-in with the `device_sso` scope returns. Otherwise it tries a `prompt=none`
|
|
3039
|
+
* request to `{baseUrl}/ou/{ouId}/oauth2/authorize` in a hidden iframe. When the server needs the
|
|
3040
|
+
* user, it redirects the page there (unless `redirect` is `false`), and the callback replaces the
|
|
3041
|
+
* session.
|
|
3042
|
+
* - Embedded mode starts an `AUTHENTICATION` flow with `ouId`, presenting the SSO session handles kept
|
|
3043
|
+
* from earlier flow steps. A flow that needs input fails with `interaction_required`; render the
|
|
3044
|
+
* sign-in for the unit instead.
|
|
3045
|
+
* - Backend mode sends the page to the backend's sign-in endpoint with `ouId`.
|
|
3046
|
+
*
|
|
3047
|
+
* A failed switch leaves the previous session as it was.
|
|
3048
|
+
*
|
|
3049
|
+
* @throws {ThunderIDAPIError} With a code from `OrganizationUnitSwitchErrorCodes`.
|
|
3050
|
+
*/
|
|
3051
|
+
async switchOrganizationUnit(organizationUnitId, options = {}) {
|
|
3052
|
+
await this.isInitialized();
|
|
3053
|
+
if (typeof organizationUnitId !== "string" || organizationUnitId.trim() === "") throw new ThunderIDAPIError("An organization unit identifier is required.", OrganizationUnitSwitchErrorCodes.InvalidOrganizationUnit, "browser", 400);
|
|
3054
|
+
if (this._backend) {
|
|
3055
|
+
location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`, organizationUnitId);
|
|
3056
|
+
await SPAUtils_default.waitTillPageRedirect();
|
|
3057
|
+
return;
|
|
3058
|
+
}
|
|
3059
|
+
const { redirect = true,...params } = options;
|
|
3060
|
+
const sm = this.getStorageManager();
|
|
3061
|
+
const config = await sm.getConfigData();
|
|
3062
|
+
if (config?.mode === "embedded") return this._switchOrganizationUnitEmbedded(organizationUnitId, config);
|
|
3063
|
+
const exchangedUser = await this._switchOrganizationUnitWithDeviceSecret(organizationUnitId, config);
|
|
3064
|
+
if (exchangedUser) return exchangedUser;
|
|
3065
|
+
let silentError;
|
|
3066
|
+
let silentUser = false;
|
|
3067
|
+
if (exchangedUser === void 0) try {
|
|
3068
|
+
silentUser = await this._authHelper.signInSilently((additional) => this._constructSilentSignInUrl(additional), (code$1, s, trc) => this._exchangeCodeForTokens(code$1, s, trc), {
|
|
3069
|
+
...params,
|
|
3070
|
+
organizationUnitId
|
|
3071
|
+
}, void 0, config?.session?.silentSignIn?.timeout, (error) => {
|
|
3072
|
+
silentError = error;
|
|
3073
|
+
});
|
|
3074
|
+
} catch (error) {
|
|
3075
|
+
throw ThunderIDBrowserClient._toSwitchError(error instanceof Error ? error.message : void 0, error);
|
|
3076
|
+
}
|
|
3077
|
+
if (silentUser && typeof silentUser === "object") {
|
|
3078
|
+
this._emitHook(Hooks_default.SignIn, silentUser);
|
|
3079
|
+
return silentUser;
|
|
3080
|
+
}
|
|
3081
|
+
if (silentError && !INTERACTION_ERRORS.includes(silentError)) throw ThunderIDBrowserClient._toSwitchError(silentError);
|
|
3082
|
+
if (!redirect) throw ThunderIDBrowserClient._toSwitchError("interaction_required");
|
|
3083
|
+
const url = await this.getSignInUrl({
|
|
3084
|
+
...params,
|
|
3085
|
+
organizationUnitId
|
|
3086
|
+
});
|
|
3087
|
+
await sm.setTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY, organizationUnitId);
|
|
3088
|
+
location.href = url;
|
|
3089
|
+
await SPAUtils_default.waitTillPageRedirect();
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Switches back-channel by exchanging the session's device secret at the unit's token endpoint.
|
|
3093
|
+
*
|
|
3094
|
+
* @returns The user, `false` when the server needs the user, or `undefined` when the session holds no
|
|
3095
|
+
* device secret.
|
|
3096
|
+
*/
|
|
3097
|
+
async _switchOrganizationUnitWithDeviceSecret(organizationUnitId, config) {
|
|
3098
|
+
let result;
|
|
3099
|
+
try {
|
|
3100
|
+
result = await this.switchOrganizationUnitWithDeviceSecret(organizationUnitId);
|
|
3101
|
+
} catch (error) {
|
|
3102
|
+
throw ThunderIDBrowserClient._toSwitchError(void 0, error);
|
|
3103
|
+
}
|
|
3104
|
+
if (!result) return;
|
|
3105
|
+
if ("error" in result) {
|
|
3106
|
+
if (INTERACTION_ERRORS.includes(result.error) || UNUSABLE_DEVICE_SECRET_ERRORS.includes(result.error)) return false;
|
|
3107
|
+
throw ThunderIDBrowserClient._toSwitchError(result.error);
|
|
3108
|
+
}
|
|
3109
|
+
const user = await this._startSession(config.clientId ?? "");
|
|
3110
|
+
this._emitHook(Hooks_default.SignIn, user);
|
|
3111
|
+
return user;
|
|
3112
|
+
}
|
|
3113
|
+
/**
|
|
3114
|
+
* Maps an OAuth error from a bounded sign-in onto the switch's documented errors.
|
|
3115
|
+
*/
|
|
3116
|
+
static _toSwitchError(oauthError, cause) {
|
|
3117
|
+
if (cause instanceof ThunderIDAPIError && Object.values(OrganizationUnitSwitchErrorCodes).includes(cause.code)) return cause;
|
|
3118
|
+
let code$1 = OrganizationUnitSwitchErrorCodes.Failed;
|
|
3119
|
+
if (oauthError === "unauthorized_client") code$1 = OrganizationUnitSwitchErrorCodes.UnauthorizedClient;
|
|
3120
|
+
else if (oauthError && INTERACTION_ERRORS.includes(oauthError)) code$1 = OrganizationUnitSwitchErrorCodes.InteractionRequired;
|
|
3121
|
+
const serverCode = oauthError ?? "switch_failed";
|
|
3122
|
+
return new ThunderIDAPIError(JSON.stringify({
|
|
3123
|
+
code: serverCode,
|
|
3124
|
+
message: { defaultValue: serverCode }
|
|
3125
|
+
}), code$1, "browser", oauthError === "unauthorized_client" ? 400 : void 0, void 0, "Switching the organization unit failed");
|
|
3126
|
+
}
|
|
3127
|
+
/**
|
|
3128
|
+
* Embedded mode: starts a sign-in flow bounded to the unit. When the SSO session is reused, the flow
|
|
3129
|
+
* completes at once and its assertion replaces the session.
|
|
3130
|
+
*/
|
|
3131
|
+
async _switchOrganizationUnitEmbedded(organizationUnitId, config) {
|
|
3132
|
+
let response;
|
|
3133
|
+
const sessionData = await this.getFlowSessions();
|
|
3134
|
+
try {
|
|
3135
|
+
response = await executeEmbeddedSignInFlow({
|
|
3136
|
+
baseUrl: config?.baseUrl,
|
|
3137
|
+
payload: {
|
|
3138
|
+
applicationId: config?.applicationId ?? "",
|
|
3139
|
+
flowType: EmbeddedFlowType.Authentication,
|
|
3140
|
+
ouId: organizationUnitId,
|
|
3141
|
+
...sessionData.length > 0 ? { sessionData } : {}
|
|
3142
|
+
},
|
|
3143
|
+
url: resolveResourceEndpoint("flowExecute", config)
|
|
3144
|
+
});
|
|
3145
|
+
} catch (error) {
|
|
3146
|
+
const serverCode = error instanceof ThunderIDAPIError ? error.serverError?.code : void 0;
|
|
3147
|
+
throw ThunderIDBrowserClient._toSwitchError(serverCode === "FES-1023" ? "unauthorized_client" : serverCode, error);
|
|
3148
|
+
}
|
|
3149
|
+
await this.storeFlowSessions(response);
|
|
3150
|
+
if (response?.flowStatus === EmbeddedSignInFlowStatus.Complete && response.assertion) {
|
|
3151
|
+
const claims = await this.decodeJwtToken(response.assertion);
|
|
3152
|
+
const iat = typeof claims["iat"] === "number" ? claims["iat"] : void 0;
|
|
3153
|
+
const exp = typeof claims["exp"] === "number" ? claims["exp"] : void 0;
|
|
3154
|
+
await this.setSession({
|
|
3155
|
+
access_token: response.assertion,
|
|
3156
|
+
created_at: iat ? iat * 1e3 : Date.now(),
|
|
3157
|
+
expires_in: exp && iat ? exp - iat : 3600,
|
|
3158
|
+
id_token: response.assertion,
|
|
3159
|
+
scope: claims["scope"],
|
|
3160
|
+
token_type: "Bearer"
|
|
3161
|
+
});
|
|
3162
|
+
const user = await this.getUser();
|
|
3163
|
+
this._emitHook(Hooks_default.SignIn, user);
|
|
3164
|
+
return user;
|
|
3165
|
+
}
|
|
3166
|
+
if (response?.flowStatus === EmbeddedSignInFlowStatus.Error) throw ThunderIDBrowserClient._toSwitchError("access_denied");
|
|
3167
|
+
throw ThunderIDBrowserClient._toSwitchError("interaction_required");
|
|
3168
|
+
}
|
|
3169
|
+
/**
|
|
3170
|
+
* Completes a switch that left the page for the unit's authorization endpoint: redeems the returned
|
|
3171
|
+
* code, or reports the returned error and keeps the previous session.
|
|
3172
|
+
*/
|
|
3173
|
+
async _completeOrganizationUnitSwitch(tokenRequestConfig) {
|
|
3174
|
+
const sm = this.getStorageManager();
|
|
3175
|
+
if (!await sm.getTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY) || SPAUtils_default.isInitializedSilentSignIn()) return;
|
|
3176
|
+
const url = new URL(window.location.href);
|
|
3177
|
+
const code$1 = url.searchParams.get(OIDCRequestConstants.Params.AUTHORIZATION_CODE);
|
|
3178
|
+
const state = url.searchParams.get(OIDCRequestConstants.Params.STATE);
|
|
3179
|
+
const error = url.searchParams.get("error");
|
|
3180
|
+
if (code$1 && state) {
|
|
3181
|
+
await sm.removeTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY);
|
|
3182
|
+
SPAUtils_default.removeAuthorizationCode();
|
|
3183
|
+
try {
|
|
3184
|
+
return await this._exchangeCodeForTokens(code$1, state, tokenRequestConfig);
|
|
3185
|
+
} catch (exchangeError) {
|
|
3186
|
+
throw ThunderIDBrowserClient._toSwitchError(void 0, exchangeError);
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
if (error) {
|
|
3190
|
+
await sm.removeTemporaryDataParameter(ORGANIZATION_UNIT_SWITCH_KEY);
|
|
3191
|
+
url.searchParams.delete("error");
|
|
3192
|
+
url.searchParams.delete("error_description");
|
|
3193
|
+
url.searchParams.delete(OIDCRequestConstants.Params.STATE);
|
|
3194
|
+
history.replaceState(null, document.title, url.toString());
|
|
3195
|
+
throw ThunderIDBrowserClient._toSwitchError(error);
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
2993
3198
|
async signInSilently(additionalParams, tokenRequestConfig) {
|
|
2994
3199
|
await this.isInitialized();
|
|
2995
3200
|
if (this._backend) return await this.isSignedIn() ? this.getUser() : false;
|
|
@@ -3286,13 +3491,14 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
3286
3491
|
const config = await this.getStorageManager().getConfigData();
|
|
3287
3492
|
const urlString = await this.getSignInUrl({
|
|
3288
3493
|
prompt: "none",
|
|
3494
|
+
response_mode: "query",
|
|
3289
3495
|
state: SILENT_SIGN_IN_STATE,
|
|
3290
3496
|
...additionalParams
|
|
3291
3497
|
});
|
|
3292
3498
|
const urlObject = new URL(urlString);
|
|
3293
|
-
urlObject.searchParams.set("response_mode", "query");
|
|
3499
|
+
if (!urlObject.searchParams.has("request_uri")) urlObject.searchParams.set("response_mode", "query");
|
|
3294
3500
|
if (this._storage === BrowserStorage_default.BrowserMemory && config.enablePKCE) {
|
|
3295
|
-
const state = urlObject.searchParams.get(OIDCRequestConstants.Params.STATE);
|
|
3501
|
+
const state = urlObject.searchParams.get(OIDCRequestConstants.Params.STATE) ?? this.lastAuthorizeRequestState;
|
|
3296
3502
|
SPAUtils_default.setPKCE(extractPkceStorageKeyFromState(state ?? ""), await this.getPKCECode(state ?? ""));
|
|
3297
3503
|
}
|
|
3298
3504
|
return urlObject.toString();
|
|
@@ -3377,6 +3583,48 @@ const copyTextToClipboard = async (text) => {
|
|
|
3377
3583
|
};
|
|
3378
3584
|
var copyTextToClipboard_default = copyTextToClipboard;
|
|
3379
3585
|
|
|
3586
|
+
//#endregion
|
|
3587
|
+
//#region src/utils/currentProjectStorage.ts
|
|
3588
|
+
/**
|
|
3589
|
+
* The `localStorage` key the current project is kept under, scoped to the vendor like the SDK's
|
|
3590
|
+
* other UI preferences.
|
|
3591
|
+
*
|
|
3592
|
+
* @param vendor - The vendor prefix.
|
|
3593
|
+
* @returns The key.
|
|
3594
|
+
*/
|
|
3595
|
+
const getCurrentProjectStorageKey = (vendor) => `${getVendorPrefix(vendor)}-current-project`;
|
|
3596
|
+
/**
|
|
3597
|
+
* Reads the project the user last chose. The current project is a client-side preference for the
|
|
3598
|
+
* management UI: it does not change the session, the tokens or what the server allows.
|
|
3599
|
+
*
|
|
3600
|
+
* @param vendor - The vendor prefix.
|
|
3601
|
+
* @returns The project, or `null` when none is kept or storage is unavailable.
|
|
3602
|
+
*/
|
|
3603
|
+
const readCurrentProject = (vendor) => {
|
|
3604
|
+
try {
|
|
3605
|
+
if (typeof window === "undefined" || !window.localStorage) return null;
|
|
3606
|
+
const stored = window.localStorage.getItem(getCurrentProjectStorageKey(vendor));
|
|
3607
|
+
const parsed = stored ? JSON.parse(stored) : null;
|
|
3608
|
+
return parsed && typeof parsed === "object" && typeof parsed.id === "string" ? parsed : null;
|
|
3609
|
+
} catch {
|
|
3610
|
+
return null;
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
/**
|
|
3614
|
+
* Keeps the project the user chose, or forgets it with `null`.
|
|
3615
|
+
*
|
|
3616
|
+
* @param vendor - The vendor prefix.
|
|
3617
|
+
* @param project - The project, or `null`.
|
|
3618
|
+
*/
|
|
3619
|
+
const writeCurrentProject = (vendor, project) => {
|
|
3620
|
+
try {
|
|
3621
|
+
if (typeof window === "undefined" || !window.localStorage) return;
|
|
3622
|
+
const key = getCurrentProjectStorageKey(vendor);
|
|
3623
|
+
if (project) window.localStorage.setItem(key, JSON.stringify(project));
|
|
3624
|
+
else window.localStorage.removeItem(key);
|
|
3625
|
+
} catch {}
|
|
3626
|
+
};
|
|
3627
|
+
|
|
3380
3628
|
//#endregion
|
|
3381
3629
|
//#region src/utils/handleWebAuthnAuthentication.ts
|
|
3382
3630
|
const logger$1 = createPackageComponentLogger("@thunderid/browser", "WebAuthn");
|
|
@@ -4228,5 +4476,5 @@ const normalizeBorderRadius = (raw) => {
|
|
|
4228
4476
|
var normalizeBorderRadius_default = normalizeBorderRadius;
|
|
4229
4477
|
|
|
4230
4478
|
//#endregion
|
|
4231
|
-
export { ACCESS_TOKEN_INVALID, ANONYMOUS_ANIMAL_ICONS, ANONYMOUS_ENTITY_ICONS, AVATAR_GRADIENT_COUNT, AVATAR_URI_SCHEME, AuthenticationHelper_default as AuthenticationHelper, BACKEND_REQUEST_HEADER, BackendClient_default as BackendClient, BackendHttpClient_default as BackendHttpClient, Hooks as BrowserHooks, BrowserStorage_default as BrowserStorage, CUSTOM_GRANT_CONFIG, ERROR, ERROR_DESCRIPTION, FetchHttpClient_default as FetchHttpClient, Hooks_default as Hooks, LocalStore_default as LocalStore, MemoryStore_default as MemoryStore, REFRESH_ACCESS_TOKEN_ERR0R, SILENT_SIGN_IN_SIGNED_IN, SILENT_SIGN_IN_SIGNED_OUT, SILENT_SIGN_IN_STATE, SILENT_SIGN_IN_TIMEOUT, SPACryptoUtils_default as SPACryptoUtils, SPAHelper_default as SPAHelper, SPAUtils_default as SPAUtils, STATE_QUERY, SessionStore_default as SessionStore, TOKEN_REQUEST_CONFIG_KEY, ThunderIDBrowserClient_default as ThunderIDBrowserClient, buildAvatarSpec_default as buildAvatarSpec, copyTextToClipboard_default as copyTextToClipboard, createClassObserver, createHttpClientFetcher_default as createHttpClientFetcher, createMediaQueryListener, deriveAvatarContent, detectThemeMode, extractAvatarParamsFromUri_default as extractAvatarParamsFromUri, generateAvatarDataUri_default as generateAvatarDataUri, getActiveTheme_default as getActiveTheme, handleWebAuthnAuthentication_default as handleWebAuthnAuthentication, hasAuthParamsInUrl_default as hasAuthParamsInUrl, hasCalledForThisInstanceInUrl_default as hasCalledForThisInstanceInUrl, http_default as http, isAvatarUri_default as isAvatarUri, navigate_default as navigate, normalizeBorderRadius_default as normalizeBorderRadius, pickAnonymousAvatarName_default as pickAnonymousAvatarName, pickAnonymousEntityName_default as pickAnonymousEntityName, resolveEmojiUrisInHtml_default as resolveEmojiUrisInHtml, resolveLogoUri_default as resolveLogoUri };
|
|
4479
|
+
export { ACCESS_TOKEN_INVALID, ANONYMOUS_ANIMAL_ICONS, ANONYMOUS_ENTITY_ICONS, AVATAR_GRADIENT_COUNT, AVATAR_URI_SCHEME, AuthenticationHelper_default as AuthenticationHelper, BACKEND_REQUEST_HEADER, BackendClient_default as BackendClient, BackendHttpClient_default as BackendHttpClient, Hooks as BrowserHooks, BrowserStorage_default as BrowserStorage, CUSTOM_GRANT_CONFIG, ERROR, ERROR_DESCRIPTION, FetchHttpClient_default as FetchHttpClient, Hooks_default as Hooks, LocalStore_default as LocalStore, MemoryStore_default as MemoryStore, REFRESH_ACCESS_TOKEN_ERR0R, SILENT_SIGN_IN_SIGNED_IN, SILENT_SIGN_IN_SIGNED_OUT, SILENT_SIGN_IN_STATE, SILENT_SIGN_IN_TIMEOUT, SPACryptoUtils_default as SPACryptoUtils, SPAHelper_default as SPAHelper, SPAUtils_default as SPAUtils, STATE_QUERY, SessionStore_default as SessionStore, TOKEN_REQUEST_CONFIG_KEY, ThunderIDBrowserClient_default as ThunderIDBrowserClient, buildAvatarSpec_default as buildAvatarSpec, copyTextToClipboard_default as copyTextToClipboard, createClassObserver, createHttpClientFetcher_default as createHttpClientFetcher, createMediaQueryListener, deriveAvatarContent, detectThemeMode, extractAvatarParamsFromUri_default as extractAvatarParamsFromUri, generateAvatarDataUri_default as generateAvatarDataUri, getActiveTheme_default as getActiveTheme, getCurrentProjectStorageKey, handleWebAuthnAuthentication_default as handleWebAuthnAuthentication, hasAuthParamsInUrl_default as hasAuthParamsInUrl, hasCalledForThisInstanceInUrl_default as hasCalledForThisInstanceInUrl, http_default as http, isAvatarUri_default as isAvatarUri, navigate_default as navigate, normalizeBorderRadius_default as normalizeBorderRadius, pickAnonymousAvatarName_default as pickAnonymousAvatarName, pickAnonymousEntityName_default as pickAnonymousEntityName, readCurrentProject, resolveEmojiUrisInHtml_default as resolveEmojiUrisInHtml, resolveLogoUri_default as resolveLogoUri, writeCurrentProject };
|
|
4232
4480
|
//# sourceMappingURL=index.js.map
|