@thunderid/browser 1.3.1 → 1.4.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 +109 -0
- package/dist/BackendClient.d.ts.map +1 -0
- package/dist/BackendHttpClient.d.ts +20 -0
- package/dist/BackendHttpClient.d.ts.map +1 -0
- package/dist/FetchHttpClient.d.ts +1 -0
- package/dist/FetchHttpClient.d.ts.map +1 -1
- package/dist/ThunderIDBrowserClient.d.ts +16 -0
- package/dist/ThunderIDBrowserClient.d.ts.map +1 -1
- package/dist/cjs/index.cjs +425 -32
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +424 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { default as ThunderIDBrowserClient } from './ThunderIDBrowserClient';
|
|
5
5
|
export { default as FetchHttpClient } from './FetchHttpClient';
|
|
6
|
+
export { default as BackendClient, BACKEND_REQUEST_HEADER } from './BackendClient';
|
|
7
|
+
export { default as BackendHttpClient } from './BackendHttpClient';
|
|
6
8
|
export { default as Hooks, Hooks as BrowserHooks } from './constants/Hooks';
|
|
7
9
|
export * from './constants/SPAConstants';
|
|
8
10
|
export { default as BrowserStorage } from './models/BrowserStorage';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;GAEG;AAGH,OAAO,EAAC,OAAO,IAAI,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,mBAAmB,CAAC;
|
|
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, getUsersMe, isEmojiUri, resolveResourceEndpoint } from "@thunderid/javascript";
|
|
3
|
+
import { DEFAULT_THEME, HttpClient, OIDCRequestConstants, ThunderIDAuthException, ThunderIDJavaScriptClient, ThunderIDRuntimeError, TokenConstants, arrayBufferToBase64url, base64urlToArrayBuffer, createPackageComponentLogger, extractEmojiFromUri, extractPkceStorageKeyFromState, generateFlattenedUserProfile, getUsersMe, isEmojiUri, resolveBackendEndpoints, resolveResourceEndpoint } from "@thunderid/javascript";
|
|
4
4
|
import base64url from "base64url";
|
|
5
5
|
import sha256 from "fast-sha256";
|
|
6
6
|
import { createLocalJWKSet, jwtVerify } from "jose";
|
|
@@ -33,38 +33,226 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
}) : target, mod));
|
|
34
34
|
|
|
35
35
|
//#endregion
|
|
36
|
-
//#region src/
|
|
36
|
+
//#region src/BackendClient.ts
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* Header every backend request carries. A cross-origin page cannot set it without a CORS preflight,
|
|
39
|
+
* which the backend never answers, so it keeps the cookie from being used cross-site.
|
|
39
40
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
41
|
+
const BACKEND_REQUEST_HEADER = "X-Requested-With";
|
|
42
|
+
const BACKEND_REQUEST_HEADER_VALUE = "XMLHttpRequest";
|
|
43
|
+
/** A check on focus is skipped when the last one is more recent than this, in milliseconds. */
|
|
44
|
+
const FOCUS_CHECK_THROTTLE = 5e3;
|
|
45
|
+
/**
|
|
46
|
+
* Talks to the app's backend when sign-in runs there: reads the session, refreshes it, and starts and ends it. The
|
|
47
|
+
* browser never holds a token; the backend keeps them behind an `HttpOnly` cookie.
|
|
48
|
+
*/
|
|
49
|
+
var BackendClient = class BackendClient {
|
|
50
|
+
session;
|
|
51
|
+
refreshing;
|
|
52
|
+
hasLoadedSession = false;
|
|
53
|
+
/** Whether the session last seen was signed in, so a later read can tell it has ended. */
|
|
54
|
+
wasSignedIn = false;
|
|
55
|
+
lastCheck = 0;
|
|
56
|
+
signedOutListeners = [];
|
|
57
|
+
constructor(endpoints) {
|
|
58
|
+
this.endpoints = endpoints;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Calls the listener when a signed-in session turns out to have ended without this client signing
|
|
62
|
+
* out: another app signed the user out, an administrator ended the session, or it timed out.
|
|
63
|
+
*/
|
|
64
|
+
onSignedOut(listener) {
|
|
65
|
+
this.signedOutListeners.push(listener);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Records that the session has ended, and tells the listeners when it had been signed in.
|
|
69
|
+
*/
|
|
70
|
+
markSignedOut() {
|
|
71
|
+
this.session = Promise.resolve({ isSignedIn: false });
|
|
72
|
+
this.hasLoadedSession = true;
|
|
73
|
+
if (this.wasSignedIn) {
|
|
74
|
+
this.wasSignedIn = false;
|
|
75
|
+
this.signedOutListeners.forEach((listener) => listener());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Asks the backend whether the session is still live. The check neither refreshes the session nor
|
|
80
|
+
* counts as activity, so it can be polled without keeping an idle session alive.
|
|
81
|
+
*
|
|
82
|
+
* @returns Whether the session is live. A failed check reports the last known state.
|
|
83
|
+
*/
|
|
84
|
+
async checkSession() {
|
|
85
|
+
this.lastCheck = Date.now();
|
|
86
|
+
try {
|
|
87
|
+
const response = await this.send(this.endpoints.checkSession, "GET");
|
|
88
|
+
if (!response.ok) return this.wasSignedIn;
|
|
89
|
+
const { isSignedIn } = await response.json();
|
|
90
|
+
if (!isSignedIn) this.markSignedOut();
|
|
91
|
+
return isSignedIn;
|
|
92
|
+
} catch {
|
|
93
|
+
return this.wasSignedIn;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Watches for the session ending while the page is open: checks it whenever the page gets focus or
|
|
98
|
+
* becomes visible again, and every `pollSeconds` while it is visible when that is positive.
|
|
99
|
+
*
|
|
100
|
+
* @returns A function that stops watching.
|
|
101
|
+
*/
|
|
102
|
+
watch(pollSeconds) {
|
|
103
|
+
const checkIfSignedIn = () => {
|
|
104
|
+
if (this.wasSignedIn && document.visibilityState === "visible") this.checkSession();
|
|
105
|
+
};
|
|
106
|
+
const onFocus = () => {
|
|
107
|
+
if (Date.now() - this.lastCheck >= FOCUS_CHECK_THROTTLE) checkIfSignedIn();
|
|
108
|
+
};
|
|
109
|
+
document.addEventListener("visibilitychange", onFocus);
|
|
110
|
+
window.addEventListener("focus", onFocus);
|
|
111
|
+
const timer = pollSeconds > 0 ? setInterval(checkIfSignedIn, pollSeconds * 1e3) : void 0;
|
|
112
|
+
return () => {
|
|
113
|
+
document.removeEventListener("visibilitychange", onFocus);
|
|
114
|
+
window.removeEventListener("focus", onFocus);
|
|
115
|
+
if (timer) clearInterval(timer);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Returns the session. The result is cached until a sign-in, sign-out, or refresh changes it, so
|
|
120
|
+
* repeated sign-in checks do not reach the server each time.
|
|
121
|
+
*
|
|
122
|
+
* @param reload - Read the session from the server even when one is cached.
|
|
123
|
+
*/
|
|
124
|
+
getSession(reload = false) {
|
|
125
|
+
if (reload) this.session = void 0;
|
|
126
|
+
this.session ??= this.loadSession().catch((error) => {
|
|
127
|
+
this.session = void 0;
|
|
128
|
+
throw error;
|
|
129
|
+
}).finally(() => {
|
|
130
|
+
this.hasLoadedSession = true;
|
|
131
|
+
});
|
|
132
|
+
return this.session;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Whether this client talks to exactly these endpoints.
|
|
136
|
+
*/
|
|
137
|
+
hasEndpoints(endpoints) {
|
|
138
|
+
return Object.keys(endpoints).every((key) => key === "bypass" ? JSON.stringify(this.endpoints.bypass) === JSON.stringify(endpoints.bypass) : this.endpoints[key] === endpoints[key]);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Whether the first session read is still in flight, so it is not yet known whether the user is
|
|
142
|
+
* signed in.
|
|
143
|
+
*/
|
|
144
|
+
isLoading() {
|
|
145
|
+
return !this.hasLoadedSession;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Refreshes the session once, sharing one request between concurrent callers.
|
|
149
|
+
*
|
|
150
|
+
* @returns Whether the session was refreshed. When it was not, the session is now signed out.
|
|
151
|
+
*/
|
|
152
|
+
refresh() {
|
|
153
|
+
this.refreshing ??= this.send(this.endpoints.refresh, "POST").then((response) => {
|
|
154
|
+
if (response.ok) this.session = void 0;
|
|
155
|
+
else this.markSignedOut();
|
|
156
|
+
return response.ok;
|
|
157
|
+
}).finally(() => {
|
|
158
|
+
this.refreshing = void 0;
|
|
159
|
+
});
|
|
160
|
+
return this.refreshing;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The URL that starts sign-in at the backend and comes back to `returnTo`.
|
|
164
|
+
*/
|
|
165
|
+
getSignInUrl(returnTo) {
|
|
166
|
+
return `${this.endpoints.signIn}?${new URLSearchParams({ returnTo }).toString()}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Ends the backend session.
|
|
170
|
+
*
|
|
171
|
+
* @returns The URL the browser visits to end the session at the authorization server.
|
|
172
|
+
*/
|
|
173
|
+
async signOut() {
|
|
174
|
+
const response = await this.send(this.endpoints.signOut, "POST");
|
|
175
|
+
this.wasSignedIn = false;
|
|
176
|
+
this.session = Promise.resolve({ isSignedIn: false });
|
|
177
|
+
if (!response.ok) throw new ThunderIDAuthException("SPA-BACKEND_CLIENT-SO-SE01", "Sign out failed.", `The backend sign-out endpoint returned ${response.status}.`);
|
|
178
|
+
return (await response.json()).redirectUrl;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Maps an API URL to its backend proxy URL.
|
|
182
|
+
*
|
|
183
|
+
* @returns The proxy URL, or `undefined` when the URL is not under the API base and so cannot be
|
|
184
|
+
* sent with the session's credentials.
|
|
185
|
+
*/
|
|
186
|
+
toProxyUrl(url) {
|
|
187
|
+
const { apiBaseUrl, proxy } = this.endpoints;
|
|
188
|
+
let rest;
|
|
189
|
+
if (url === apiBaseUrl || url.startsWith(`${apiBaseUrl}/`) || url.startsWith(`${apiBaseUrl}?`)) rest = url.slice(apiBaseUrl.length);
|
|
190
|
+
else if (url.startsWith("/") && !url.startsWith("//")) rest = url;
|
|
191
|
+
else return;
|
|
192
|
+
return `${proxy}${rest.startsWith("/") ? rest : `/${rest}`}`;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Whether a request to this URL skips the proxy and goes straight from the browser.
|
|
196
|
+
*/
|
|
197
|
+
isBypassed(url) {
|
|
198
|
+
return this.endpoints.bypass.urls.some((base) => url === base || url.startsWith(`${base}/`) || url.startsWith(`${base}?`));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Whether requests that skip the proxy carry the access token.
|
|
202
|
+
*/
|
|
203
|
+
attachesTokenOnBypass() {
|
|
204
|
+
return this.endpoints.bypass.attachToken;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Gets an access token for the requests that skip the proxy from the backend's token endpoint. It comes without a
|
|
208
|
+
* refresh token: when it expires, the caller asks again.
|
|
209
|
+
*
|
|
210
|
+
* @returns The token response, as the backend sent it.
|
|
211
|
+
*/
|
|
212
|
+
async requestAccessToken() {
|
|
213
|
+
let response = await this.send(this.endpoints.token, "POST");
|
|
214
|
+
if (response.status === 401) {
|
|
215
|
+
const { error } = await response.json().catch(() => ({}));
|
|
216
|
+
if (error === "session_expired" && await this.refresh()) response = await this.send(this.endpoints.token, "POST");
|
|
217
|
+
else if (error === "login_required") this.markSignedOut();
|
|
218
|
+
}
|
|
219
|
+
if (!response.ok) throw new ThunderIDAuthException("SPA-BACKEND_CLIENT-RAT-SE01", "Failed to get an access token.", `The backend token endpoint returned ${response.status}.`);
|
|
220
|
+
return await response.json();
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The headers and credentials mode every backend request is sent with.
|
|
224
|
+
*/
|
|
225
|
+
static requestInit(headers = {}) {
|
|
226
|
+
return {
|
|
227
|
+
credentials: "same-origin",
|
|
228
|
+
headers: {
|
|
229
|
+
...headers,
|
|
230
|
+
[BACKEND_REQUEST_HEADER]: BACKEND_REQUEST_HEADER_VALUE
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
async loadSession() {
|
|
235
|
+
let response = await this.send(this.endpoints.session, "GET");
|
|
236
|
+
if (response.status === 401 && await this.refresh()) response = await this.send(this.endpoints.session, "GET");
|
|
237
|
+
if (response.status === 401) return this.signedOutSession();
|
|
238
|
+
if (!response.ok) throw new ThunderIDAuthException("SPA-BACKEND_CLIENT-GS-SE01", "Failed to read the session.", `The backend session endpoint returned ${response.status}.`);
|
|
239
|
+
const session = await response.json();
|
|
240
|
+
if (!session.isSignedIn) return this.signedOutSession();
|
|
241
|
+
this.wasSignedIn = true;
|
|
242
|
+
return session;
|
|
243
|
+
}
|
|
244
|
+
signedOutSession() {
|
|
245
|
+
if (this.wasSignedIn) queueMicrotask(() => this.markSignedOut());
|
|
246
|
+
return { isSignedIn: false };
|
|
247
|
+
}
|
|
248
|
+
send(url, method) {
|
|
249
|
+
return fetch(url, {
|
|
250
|
+
method,
|
|
251
|
+
...BackendClient.requestInit({ Accept: "application/json" })
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
var BackendClient_default = BackendClient;
|
|
68
256
|
|
|
69
257
|
//#endregion
|
|
70
258
|
//#region src/FetchHttpClient.ts
|
|
@@ -82,6 +270,9 @@ var FetchHttpClient = class FetchHttpClient extends HttpClient {
|
|
|
82
270
|
if (!this.instances.has(instanceId)) this.instances.set(instanceId, new FetchHttpClient(isHandlerEnabled, attachToken));
|
|
83
271
|
return this.instances.get(instanceId);
|
|
84
272
|
}
|
|
273
|
+
static setInstance(instanceId, client) {
|
|
274
|
+
this.instances.set(instanceId, client);
|
|
275
|
+
}
|
|
85
276
|
static destroyInstance(instanceId = 0) {
|
|
86
277
|
this.instances.delete(instanceId);
|
|
87
278
|
}
|
|
@@ -141,6 +332,108 @@ var FetchHttpClient = class FetchHttpClient extends HttpClient {
|
|
|
141
332
|
};
|
|
142
333
|
var FetchHttpClient_default = FetchHttpClient;
|
|
143
334
|
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/BackendHttpClient.ts
|
|
337
|
+
/**
|
|
338
|
+
* The HTTP client used when sign-in runs on the backend. It sends each request through the backend's
|
|
339
|
+
* API proxy with the session cookie instead of attaching a token, and refreshes the session once
|
|
340
|
+
* when the backend reports
|
|
341
|
+
* it expired. Requests under `bypass` go straight there with the cookies and, unless turned off, the
|
|
342
|
+
* access token the backend issued.
|
|
343
|
+
*/
|
|
344
|
+
const hasBackendError = (error, code$1) => error?.response?.status === 401 && error.response.data?.error === code$1;
|
|
345
|
+
const isSessionExpired = (error) => hasBackendError(error, "session_expired");
|
|
346
|
+
var BackendHttpClient = class extends FetchHttpClient_default {
|
|
347
|
+
/**
|
|
348
|
+
* @param backend - The backend client.
|
|
349
|
+
* @param getAccessToken - Returns the access token for bypassed requests; `renew` asks for a new one.
|
|
350
|
+
*/
|
|
351
|
+
constructor(backend, getAccessToken) {
|
|
352
|
+
super(true);
|
|
353
|
+
this.backend = backend;
|
|
354
|
+
this.getAccessToken = getAccessToken;
|
|
355
|
+
}
|
|
356
|
+
async transport(config) {
|
|
357
|
+
if (this.backend.isBypassed(config.url ?? "")) return this.sendBypassed(config);
|
|
358
|
+
const proxyUrl = this.backend.toProxyUrl(config.url ?? "");
|
|
359
|
+
if (!proxyUrl) throw Object.assign(/* @__PURE__ */ new Error(`"${config.url}" is not under the backend API base, so it cannot be sent.`), {
|
|
360
|
+
code: "BACKEND_UNSUPPORTED_URL",
|
|
361
|
+
config
|
|
362
|
+
});
|
|
363
|
+
const send = () => super.transport({
|
|
364
|
+
...config,
|
|
365
|
+
...BackendClient_default.requestInit(config.headers),
|
|
366
|
+
url: proxyUrl
|
|
367
|
+
});
|
|
368
|
+
try {
|
|
369
|
+
return await send();
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (isSessionExpired(error) && await this.backend.refresh()) return send();
|
|
372
|
+
if (hasBackendError(error, "login_required")) this.backend.markSignedOut();
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Sends a request straight to its URL, skipping the proxy, with the cookies and the access token.
|
|
378
|
+
* When the API rejects the token, it gets a new one and retries once.
|
|
379
|
+
*/
|
|
380
|
+
async sendBypassed(config) {
|
|
381
|
+
if (!this.backend.attachesTokenOnBypass()) return super.transport({
|
|
382
|
+
...config,
|
|
383
|
+
credentials: "include"
|
|
384
|
+
});
|
|
385
|
+
const send = async (renew) => super.transport({
|
|
386
|
+
...config,
|
|
387
|
+
credentials: "include",
|
|
388
|
+
headers: {
|
|
389
|
+
...config.headers,
|
|
390
|
+
Authorization: `Bearer ${await this.getAccessToken(renew)}`
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
try {
|
|
394
|
+
return await send(false);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
if (error.response?.status === 401) return send(true);
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var BackendHttpClient_default = BackendHttpClient;
|
|
402
|
+
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/constants/Hooks.ts
|
|
405
|
+
/**
|
|
406
|
+
* Event hook names for attaching callbacks via `ThunderIDBrowserClient.on()`.
|
|
407
|
+
*/
|
|
408
|
+
let Hooks = /* @__PURE__ */ function(Hooks$1) {
|
|
409
|
+
Hooks$1["SignIn"] = "sign-in";
|
|
410
|
+
Hooks$1["SignOut"] = "sign-out";
|
|
411
|
+
Hooks$1["Initialize"] = "initialize";
|
|
412
|
+
Hooks$1["HttpRequestStart"] = "http-request-start";
|
|
413
|
+
Hooks$1["HttpRequestFinish"] = "http-request-finish";
|
|
414
|
+
Hooks$1["HttpRequestError"] = "http-request-error";
|
|
415
|
+
Hooks$1["HttpRequestSuccess"] = "http-request-success";
|
|
416
|
+
Hooks$1["RevokeAccessToken"] = "revoke-access-token";
|
|
417
|
+
Hooks$1["CustomGrant"] = "custom-grant";
|
|
418
|
+
Hooks$1["SignOutFailed"] = "sign-out-failed";
|
|
419
|
+
return Hooks$1;
|
|
420
|
+
}({});
|
|
421
|
+
var Hooks_default = Hooks;
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/constants/SPAConstants.ts
|
|
425
|
+
const ERROR = "error";
|
|
426
|
+
const ERROR_DESCRIPTION = "error_description";
|
|
427
|
+
const CUSTOM_GRANT_CONFIG = "custom_grant_config";
|
|
428
|
+
const STATE_QUERY = "state";
|
|
429
|
+
const SILENT_SIGN_IN_STATE = "sign-in-silently";
|
|
430
|
+
const SILENT_SIGN_IN_TIMEOUT = 1e4;
|
|
431
|
+
const ACCESS_TOKEN_INVALID = "Access token is invalid";
|
|
432
|
+
const REFRESH_ACCESS_TOKEN_ERR0R = "refresh-access-token-error";
|
|
433
|
+
const TOKEN_REQUEST_CONFIG_KEY = "token_request_config";
|
|
434
|
+
const SILENT_SIGN_IN_SIGNED_IN = "silent_sign_in_signed_in";
|
|
435
|
+
const SILENT_SIGN_IN_SIGNED_OUT = "silent_sign_in_signed_out";
|
|
436
|
+
|
|
144
437
|
//#endregion
|
|
145
438
|
//#region src/models/BrowserStorage.ts
|
|
146
439
|
/**
|
|
@@ -2513,6 +2806,9 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2513
2806
|
_hookCallbacks = /* @__PURE__ */ new Map();
|
|
2514
2807
|
_initialized = false;
|
|
2515
2808
|
_startedInitialize = false;
|
|
2809
|
+
_backend;
|
|
2810
|
+
_stopBackendWatch;
|
|
2811
|
+
_backendTokenRequest;
|
|
2516
2812
|
constructor(instanceId = 0) {
|
|
2517
2813
|
super(void 0, new SPACryptoUtils_default());
|
|
2518
2814
|
this._browserInstanceId = instanceId;
|
|
@@ -2536,7 +2832,29 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2536
2832
|
const attachToken = async (request) => {
|
|
2537
2833
|
await this._authHelper?.attachTokenToRequestConfig(request);
|
|
2538
2834
|
};
|
|
2539
|
-
|
|
2835
|
+
const backendEndpoints = resolveBackendEndpoints(merged, window.location.origin);
|
|
2836
|
+
if (backendEndpoints) {
|
|
2837
|
+
if (!this._backend?.hasEndpoints(backendEndpoints)) {
|
|
2838
|
+
this._backend = new BackendClient_default(backendEndpoints);
|
|
2839
|
+
this._backend.onSignedOut(() => {
|
|
2840
|
+
this.getStorageManager().removeSessionData();
|
|
2841
|
+
this._emitHook(Hooks_default.SignOut);
|
|
2842
|
+
});
|
|
2843
|
+
}
|
|
2844
|
+
this._stopBackendWatch?.();
|
|
2845
|
+
const { session } = merged;
|
|
2846
|
+
this._stopBackendWatch = this._backend.watch(Number(session?.checkInterval ?? 0));
|
|
2847
|
+
this._httpClient = new BackendHttpClient_default(this._backend, (renew) => this._getBackendAccessToken(renew));
|
|
2848
|
+
FetchHttpClient_default.setInstance(this._browserInstanceId, this._httpClient);
|
|
2849
|
+
this._backend.getSession().catch((error) => {
|
|
2850
|
+
logger$2.debug("Could not read the backend session.", error);
|
|
2851
|
+
});
|
|
2852
|
+
} else {
|
|
2853
|
+
this._stopBackendWatch?.();
|
|
2854
|
+
this._stopBackendWatch = void 0;
|
|
2855
|
+
this._backend = void 0;
|
|
2856
|
+
this._httpClient = FetchHttpClient_default.getInstance(this._browserInstanceId, true, attachToken);
|
|
2857
|
+
}
|
|
2540
2858
|
this._httpClient.setHttpRequestStartCallback((request) => {
|
|
2541
2859
|
this._emitHook(Hooks_default.HttpRequestStart, request);
|
|
2542
2860
|
});
|
|
@@ -2581,10 +2899,25 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2581
2899
|
return true;
|
|
2582
2900
|
}
|
|
2583
2901
|
isLoading() {
|
|
2584
|
-
return false;
|
|
2902
|
+
return this._backend?.isLoading() ?? false;
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Whether sign-in runs on the app's backend, which holds the tokens so the browser never does.
|
|
2906
|
+
*/
|
|
2907
|
+
isBackendMode() {
|
|
2908
|
+
return this._backend !== void 0;
|
|
2909
|
+
}
|
|
2910
|
+
_rejectInBackendMode(operation) {
|
|
2911
|
+
return Promise.reject(new ThunderIDAuthException("SPA-AUTH_CLIENT-BACKEND-NS01", "Not supported when sign-in runs on the backend.", `${operation} is not available when sign-in runs on the backend, because the browser holds no tokens.`));
|
|
2585
2912
|
}
|
|
2586
2913
|
async signIn(config, authorizationCode, state, tokenRequestConfig) {
|
|
2587
2914
|
await this.isInitialized();
|
|
2915
|
+
if (this._backend) {
|
|
2916
|
+
if (config?.callOnlyOnRedirect) return;
|
|
2917
|
+
location.href = this._backend.getSignInUrl(`${window.location.pathname}${window.location.search}`);
|
|
2918
|
+
await SPAUtils_default.waitTillPageRedirect();
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2588
2921
|
if (!SPAUtils_default.canContinueSignIn(Boolean(config?.callOnlyOnRedirect), authorizationCode)) return;
|
|
2589
2922
|
delete config?.callOnlyOnRedirect;
|
|
2590
2923
|
const user = await this._signInInternal(config, authorizationCode, state, tokenRequestConfig);
|
|
@@ -2655,6 +2988,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2655
2988
|
}
|
|
2656
2989
|
async signInSilently(additionalParams, tokenRequestConfig) {
|
|
2657
2990
|
await this.isInitialized();
|
|
2991
|
+
if (this._backend) return await this.isSignedIn() ? this.getUser() : false;
|
|
2658
2992
|
if (SPAUtils_default.wasSignInCalled()) return;
|
|
2659
2993
|
const response = await this._signInSilentlyInternal(additionalParams, tokenRequestConfig);
|
|
2660
2994
|
if (response) this._emitHook(Hooks_default.SignIn, response);
|
|
@@ -2672,6 +3006,14 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2672
3006
|
sessionId = sessionIdOrAfterSignOut;
|
|
2673
3007
|
afterSignOut = afterSignOutParam;
|
|
2674
3008
|
}
|
|
3009
|
+
if (this._backend) {
|
|
3010
|
+
await this.getStorageManager().removeSessionData();
|
|
3011
|
+
const backendSignOutUrl = await this._backend.signOut();
|
|
3012
|
+
afterSignOut?.(backendSignOutUrl);
|
|
3013
|
+
location.href = backendSignOutUrl;
|
|
3014
|
+
await SPAUtils_default.waitTillPageRedirect();
|
|
3015
|
+
return backendSignOutUrl;
|
|
3016
|
+
}
|
|
2675
3017
|
const config = await this.getStorageManager().getConfigData();
|
|
2676
3018
|
let signOutUrl = "";
|
|
2677
3019
|
if (config?.rpInitiatedLogout !== false) {
|
|
@@ -2703,18 +3045,31 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2703
3045
|
}
|
|
2704
3046
|
async httpRequest(requestConfig) {
|
|
2705
3047
|
await this._validateMethod(false);
|
|
3048
|
+
if (this._backend) return this._backendRequest(requestConfig);
|
|
2706
3049
|
const response = await this._authHelper.httpRequest(this._httpClient, requestConfig, this._isHttpHandlerEnabled, this._emitHttpError, this._emitHttpFinish);
|
|
2707
3050
|
if (this._isHttpHandlerEnabled) this._emitHttpFinish();
|
|
2708
3051
|
return response;
|
|
2709
3052
|
}
|
|
2710
3053
|
async httpRequestAll(configs) {
|
|
2711
3054
|
await this._validateMethod(false);
|
|
3055
|
+
if (this._backend) return Promise.all(configs.map((requestConfig) => this._backendRequest(requestConfig)));
|
|
2712
3056
|
const responses = await this._authHelper.httpRequestAll(configs, this._httpClient, this._isHttpHandlerEnabled, this._emitHttpError, this._emitHttpFinish);
|
|
2713
3057
|
if (this._isHttpHandlerEnabled) this._emitHttpFinish();
|
|
2714
3058
|
return responses;
|
|
2715
3059
|
}
|
|
3060
|
+
async _backendRequest(requestConfig) {
|
|
3061
|
+
try {
|
|
3062
|
+
return await this._httpClient.request(requestConfig);
|
|
3063
|
+
} catch (error) {
|
|
3064
|
+
if (this._isHttpHandlerEnabled) await this._emitHttpError(error);
|
|
3065
|
+
throw error;
|
|
3066
|
+
} finally {
|
|
3067
|
+
if (this._isHttpHandlerEnabled) this._emitHttpFinish();
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
2716
3070
|
async getUser(userId) {
|
|
2717
3071
|
await this._validateMethod();
|
|
3072
|
+
if (this._backend) return (await this._backend.getSession()).user ?? {};
|
|
2718
3073
|
return super.getUser(userId);
|
|
2719
3074
|
}
|
|
2720
3075
|
/**
|
|
@@ -2738,13 +3093,38 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2738
3093
|
};
|
|
2739
3094
|
}
|
|
2740
3095
|
async getAccessToken(sessionId) {
|
|
3096
|
+
if (this._backend) return this._getBackendAccessToken();
|
|
2741
3097
|
return super.getAccessToken(sessionId);
|
|
2742
3098
|
}
|
|
3099
|
+
/**
|
|
3100
|
+
* The access token for requests under `endpoints.backend.bypass`. Like a client credentials token it
|
|
3101
|
+
* has no refresh token: it is kept in the session storage until it nears expiry, then requested again.
|
|
3102
|
+
*
|
|
3103
|
+
* @param renew - Request a new token even when the stored one is still valid.
|
|
3104
|
+
*/
|
|
3105
|
+
async _getBackendAccessToken(renew = false) {
|
|
3106
|
+
const storageManager = this.getStorageManager();
|
|
3107
|
+
const session = await storageManager.getSessionData();
|
|
3108
|
+
const expiresAt = (session?.created_at ?? 0) + Number(session?.expires_in ?? 0) * 1e3;
|
|
3109
|
+
if (!renew && session?.access_token && expiresAt - TokenConstants.Lifecycle.CLIENT_CREDENTIALS_REFRESH_MARGIN_MS > Date.now()) return session.access_token;
|
|
3110
|
+
this._backendTokenRequest ??= this._backend.requestAccessToken().then(async (response) => {
|
|
3111
|
+
await storageManager.setSessionData({
|
|
3112
|
+
...response,
|
|
3113
|
+
created_at: Date.now()
|
|
3114
|
+
});
|
|
3115
|
+
return response.access_token ?? "";
|
|
3116
|
+
}).finally(() => {
|
|
3117
|
+
this._backendTokenRequest = void 0;
|
|
3118
|
+
});
|
|
3119
|
+
return this._backendTokenRequest;
|
|
3120
|
+
}
|
|
2743
3121
|
async getDecodedIdToken(userId, idToken) {
|
|
2744
3122
|
await this._validateMethod();
|
|
3123
|
+
if (this._backend) return (await this._backend.getSession()).user ?? {};
|
|
2745
3124
|
return super.getDecodedIdToken(userId, idToken);
|
|
2746
3125
|
}
|
|
2747
3126
|
async getIdToken(userId) {
|
|
3127
|
+
if (this._backend) return this._rejectInBackendMode("getIdToken");
|
|
2748
3128
|
await this._validateMethod();
|
|
2749
3129
|
return super.getIdToken(userId);
|
|
2750
3130
|
}
|
|
@@ -2762,6 +3142,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2762
3142
|
}
|
|
2763
3143
|
async isSignedIn(userId) {
|
|
2764
3144
|
await this.isInitialized();
|
|
3145
|
+
if (this._backend) return (await this._backend.getSession()).isSignedIn;
|
|
2765
3146
|
return super.isSignedIn(userId);
|
|
2766
3147
|
}
|
|
2767
3148
|
notifySignIn(user) {
|
|
@@ -2769,10 +3150,15 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2769
3150
|
}
|
|
2770
3151
|
async isSessionActive() {
|
|
2771
3152
|
await this.isInitialized();
|
|
3153
|
+
if (this._backend) return this.isSignedIn();
|
|
2772
3154
|
return await this.getStorageManager().getSessionStatus() === "true";
|
|
2773
3155
|
}
|
|
2774
3156
|
async refreshAccessToken(userId) {
|
|
2775
3157
|
await this._validateMethod(false);
|
|
3158
|
+
if (this._backend) {
|
|
3159
|
+
if (!await this._backend.refresh()) return Promise.reject(new ThunderIDAuthException("SPA-AUTH_CLIENT-BACKEND-RF01", "Refresh failed.", "The backend could not refresh the session."));
|
|
3160
|
+
return this.getUser();
|
|
3161
|
+
}
|
|
2776
3162
|
try {
|
|
2777
3163
|
return await this._authHelper.refreshAccessToken((cfg) => this._enableRetrievingSignOutURLFromSession(cfg));
|
|
2778
3164
|
} catch (error) {
|
|
@@ -2780,6 +3166,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2780
3166
|
}
|
|
2781
3167
|
}
|
|
2782
3168
|
async revokeAccessToken(userId) {
|
|
3169
|
+
if (this._backend) return this._rejectInBackendMode("revokeAccessToken");
|
|
2783
3170
|
await this._validateMethod();
|
|
2784
3171
|
const timer = await this._spaHelper.getRefreshTimeoutTimer();
|
|
2785
3172
|
await super.revokeAccessToken(userId);
|
|
@@ -2788,6 +3175,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2788
3175
|
return true;
|
|
2789
3176
|
}
|
|
2790
3177
|
async exchangeToken(config) {
|
|
3178
|
+
if (this._backend) return this._rejectInBackendMode("exchangeToken");
|
|
2791
3179
|
if (config.signInRequired) await this._validateMethod();
|
|
2792
3180
|
if (!config.id) return Promise.reject(new ThunderIDAuthException("SPA-AUTH_CLIENT-RCG-NF01", "The custom grant request id not found.", "Set the `id` attribute on the token exchange config."));
|
|
2793
3181
|
const response = await this._authHelper.exchangeToken(config, (cfg) => this._enableRetrievingSignOutURLFromSession(cfg));
|
|
@@ -2800,6 +3188,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2800
3188
|
}
|
|
2801
3189
|
async startAutoRefreshToken() {
|
|
2802
3190
|
await this.isInitialized();
|
|
3191
|
+
if (this._backend) return;
|
|
2803
3192
|
await this._spaHelper.clearRefreshTokenTimeout();
|
|
2804
3193
|
await this._spaHelper.refreshAccessTokenAutomatically(() => this.refreshAccessToken());
|
|
2805
3194
|
}
|
|
@@ -2841,6 +3230,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends ThunderIDJavaS
|
|
|
2841
3230
|
this._addHookCallback(hook, callback);
|
|
2842
3231
|
break;
|
|
2843
3232
|
case Hooks_default.SignOut:
|
|
3233
|
+
this._addHookCallback(hook, callback);
|
|
2844
3234
|
if (await SPAUtils_default.isSignOutSuccessful(ThunderIDBrowserClient.isSignOutSuccessful.bind(ThunderIDBrowserClient), () => ThunderIDBrowserClient.clearSession())) callback();
|
|
2845
3235
|
break;
|
|
2846
3236
|
case Hooks_default.CustomGrant:
|
|
@@ -3817,5 +4207,5 @@ const normalizeBorderRadius = (raw) => {
|
|
|
3817
4207
|
var normalizeBorderRadius_default = normalizeBorderRadius;
|
|
3818
4208
|
|
|
3819
4209
|
//#endregion
|
|
3820
|
-
export { ACCESS_TOKEN_INVALID, ANONYMOUS_ANIMAL_ICONS, ANONYMOUS_ENTITY_ICONS, AVATAR_GRADIENT_COUNT, AVATAR_URI_SCHEME, AuthenticationHelper_default as AuthenticationHelper, 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 };
|
|
4210
|
+
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 };
|
|
3821
4211
|
//# sourceMappingURL=index.js.map
|