oidc-spa 7.3.0 → 8.0.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/core/AuthResponse.d.ts +5 -0
- package/core/AuthResponse.js +25 -0
- package/core/AuthResponse.js.map +1 -1
- package/core/StateData.d.ts +2 -6
- package/core/StateData.js +0 -13
- package/core/StateData.js.map +1 -1
- package/core/createOidc.d.ts +2 -2
- package/core/createOidc.js +70 -19
- package/core/createOidc.js.map +1 -1
- package/core/diagnostic.js +3 -3
- package/core/earlyInit.d.ts +16 -0
- package/core/earlyInit.js +157 -0
- package/core/earlyInit.js.map +1 -0
- package/core/index.d.ts +0 -1
- package/core/index.js +1 -3
- package/core/index.js.map +1 -1
- package/core/loginOrGoToAuthServer.js +19 -6
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/entrypoint.d.ts +1 -7
- package/entrypoint.js +3 -46
- package/entrypoint.js.map +1 -1
- package/esm/core/AuthResponse.d.ts +5 -0
- package/esm/core/AuthResponse.js +23 -0
- package/esm/core/AuthResponse.js.map +1 -1
- package/esm/core/StateData.d.ts +2 -6
- package/esm/core/StateData.js +0 -12
- package/esm/core/StateData.js.map +1 -1
- package/esm/core/createOidc.d.ts +2 -2
- package/esm/core/createOidc.js +72 -21
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/diagnostic.js +3 -3
- package/esm/core/earlyInit.d.ts +16 -0
- package/esm/core/earlyInit.js +152 -0
- package/esm/core/earlyInit.js.map +1 -0
- package/esm/core/index.d.ts +0 -1
- package/esm/core/index.js +0 -1
- package/esm/core/index.js.map +1 -1
- package/esm/core/loginOrGoToAuthServer.js +19 -6
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/entrypoint.d.ts +1 -7
- package/esm/entrypoint.js +1 -45
- package/esm/entrypoint.js.map +1 -1
- package/esm/keycloak/keycloak-js/Keycloak.d.ts +4 -0
- package/esm/keycloak/keycloak-js/Keycloak.js +148 -173
- package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/esm/mock/oidc.js +15 -4
- package/esm/mock/oidc.js.map +1 -1
- package/esm/mock/react.d.ts +1 -1
- package/esm/mock/react.js +1 -1
- package/esm/react/react.d.ts +1 -1
- package/esm/react/react.js +2 -10
- package/esm/react/react.js.map +1 -1
- package/keycloak/keycloak-js/Keycloak.d.ts +4 -0
- package/keycloak/keycloak-js/Keycloak.js +148 -173
- package/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/mock/oidc.js +15 -4
- package/mock/oidc.js.map +1 -1
- package/mock/react.d.ts +1 -1
- package/mock/react.js +1 -1
- package/package.json +1 -1
- package/react/react.d.ts +1 -1
- package/react/react.js +1 -9
- package/react/react.js.map +1 -1
- package/src/core/AuthResponse.ts +36 -0
- package/src/core/StateData.ts +2 -22
- package/src/core/createOidc.ts +108 -24
- package/src/core/diagnostic.ts +3 -3
- package/src/core/earlyInit.ts +213 -0
- package/src/core/index.ts +0 -1
- package/src/core/loginOrGoToAuthServer.ts +24 -6
- package/src/entrypoint.ts +1 -69
- package/src/keycloak/keycloak-js/Keycloak.ts +167 -228
- package/src/mock/oidc.ts +15 -4
- package/src/mock/react.tsx +1 -1
- package/src/react/react.tsx +2 -18
- package/core/handleOidcCallback.d.ts +0 -13
- package/core/handleOidcCallback.js +0 -228
- package/core/handleOidcCallback.js.map +0 -1
- package/core/initialLocationHref.d.ts +0 -1
- package/core/initialLocationHref.js +0 -8
- package/core/initialLocationHref.js.map +0 -1
- package/esm/core/handleOidcCallback.d.ts +0 -13
- package/esm/core/handleOidcCallback.js +0 -223
- package/esm/core/handleOidcCallback.js.map +0 -1
- package/esm/core/initialLocationHref.d.ts +0 -1
- package/esm/core/initialLocationHref.js +0 -5
- package/esm/core/initialLocationHref.js.map +0 -1
- package/src/core/handleOidcCallback.ts +0 -318
- package/src/core/initialLocationHref.ts +0 -5
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getStateData,
|
|
3
|
-
markStateDataAsProcessedByCallback,
|
|
4
|
-
getIsStatQueryParamValue,
|
|
5
|
-
type StateData
|
|
6
|
-
} from "./StateData";
|
|
7
|
-
import { assert, id } from "../vendor/frontend/tsafe";
|
|
8
|
-
import type { AuthResponse } from "./AuthResponse";
|
|
9
|
-
import { initialLocationHref } from "./initialLocationHref";
|
|
10
|
-
import { encryptAuthResponse } from "./iframeMessageProtection";
|
|
11
|
-
|
|
12
|
-
const globalContext = {
|
|
13
|
-
previousCall: id<{ isHandled: boolean } | undefined>(undefined)
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function handleOidcCallback(): { isHandled: boolean } {
|
|
17
|
-
if (globalContext.previousCall !== undefined) {
|
|
18
|
-
return globalContext.previousCall;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return (globalContext.previousCall = handleOidcCallback_nonMemoized());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
25
|
-
const location_urlObj = new URL(initialLocationHref);
|
|
26
|
-
|
|
27
|
-
const stateUrlParamValue_wrap = (() => {
|
|
28
|
-
fragment: {
|
|
29
|
-
const stateUrlParamValue = new URLSearchParams(location_urlObj.hash.replace(/^#/, "")).get(
|
|
30
|
-
"state"
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
if (stateUrlParamValue === null) {
|
|
34
|
-
break fragment;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!getIsStatQueryParamValue({ maybeStateUrlParamValue: stateUrlParamValue })) {
|
|
38
|
-
break fragment;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return { stateUrlParamValue, isFragment: true };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
query: {
|
|
45
|
-
const stateUrlParamValue = location_urlObj.searchParams.get("state");
|
|
46
|
-
|
|
47
|
-
if (stateUrlParamValue === null) {
|
|
48
|
-
break query;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!getIsStatQueryParamValue({ maybeStateUrlParamValue: stateUrlParamValue })) {
|
|
52
|
-
break query;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
location_urlObj.searchParams.get("client_id") !== null &&
|
|
57
|
-
location_urlObj.searchParams.get("response_type") !== null &&
|
|
58
|
-
location_urlObj.searchParams.get("redirect_uri") !== null
|
|
59
|
-
) {
|
|
60
|
-
// NOTE: We are probably in a Keycloakify theme and oidc-spa was loaded by mistake.
|
|
61
|
-
break query;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { stateUrlParamValue, isFragment: false };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return undefined;
|
|
68
|
-
})();
|
|
69
|
-
|
|
70
|
-
if (stateUrlParamValue_wrap === undefined) {
|
|
71
|
-
const backForwardTracker = readBackForwardTracker();
|
|
72
|
-
|
|
73
|
-
if (backForwardTracker !== undefined) {
|
|
74
|
-
writeBackForwardTracker({
|
|
75
|
-
backForwardTracker: {
|
|
76
|
-
...backForwardTracker,
|
|
77
|
-
hasExitedCallback: true
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return { isHandled: false };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const isHandled = true;
|
|
86
|
-
|
|
87
|
-
const { stateUrlParamValue, isFragment } = stateUrlParamValue_wrap;
|
|
88
|
-
|
|
89
|
-
console.log = () => {};
|
|
90
|
-
console.warn = () => {};
|
|
91
|
-
console.error = () => {};
|
|
92
|
-
console.debug = () => {};
|
|
93
|
-
|
|
94
|
-
const stateData = getStateData({ stateUrlParamValue });
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
stateData === undefined ||
|
|
98
|
-
(stateData.context === "redirect" && stateData.hasBeenProcessedByCallback)
|
|
99
|
-
) {
|
|
100
|
-
const historyMethod: "back" | "forward" = (() => {
|
|
101
|
-
const backForwardTracker = readBackForwardTracker();
|
|
102
|
-
|
|
103
|
-
if (backForwardTracker === undefined) {
|
|
104
|
-
return "back";
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (!backForwardTracker.hasExitedCallback) {
|
|
108
|
-
return backForwardTracker.previousHistoryMethod;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
switch (backForwardTracker.previousHistoryMethod) {
|
|
112
|
-
case "back":
|
|
113
|
-
return "forward";
|
|
114
|
-
case "forward":
|
|
115
|
-
return "back";
|
|
116
|
-
}
|
|
117
|
-
})();
|
|
118
|
-
|
|
119
|
-
writeBackForwardTracker({
|
|
120
|
-
backForwardTracker: {
|
|
121
|
-
previousHistoryMethod: historyMethod,
|
|
122
|
-
hasExitedCallback: false
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
setTimeout(() => {
|
|
127
|
-
reloadOnBfCacheNavigation();
|
|
128
|
-
|
|
129
|
-
window.history[historyMethod]();
|
|
130
|
-
|
|
131
|
-
// NOTE: This is a "better than nothing" approach.
|
|
132
|
-
// Under some circumstances it's possible to get stuck on this url
|
|
133
|
-
// if there is no "next" page in the history for example, navigating
|
|
134
|
-
// forward is a NoOp. So in that case it's better to reload the same route
|
|
135
|
-
// with just the authResponse removed from the url to avoid re-entering here.
|
|
136
|
-
setTimeout(() => {
|
|
137
|
-
const { protocol, host, pathname, hash } = window.location;
|
|
138
|
-
window.location.href = `${protocol}//${host}${pathname}${hash}`;
|
|
139
|
-
}, 350);
|
|
140
|
-
}, 0);
|
|
141
|
-
|
|
142
|
-
return { isHandled };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const authResponse: AuthResponse = { state: "" };
|
|
146
|
-
|
|
147
|
-
for (const [key, value] of isFragment
|
|
148
|
-
? new URLSearchParams(location_urlObj.hash.replace(/^#/, ""))
|
|
149
|
-
: location_urlObj.searchParams) {
|
|
150
|
-
authResponse[key] = value;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
assert(authResponse.state !== "", "063965");
|
|
154
|
-
|
|
155
|
-
switch (stateData.context) {
|
|
156
|
-
case "iframe":
|
|
157
|
-
encryptAuthResponse({
|
|
158
|
-
authResponse
|
|
159
|
-
}).then(({ encryptedMessage }) => parent.postMessage(encryptedMessage, location.origin));
|
|
160
|
-
break;
|
|
161
|
-
case "redirect":
|
|
162
|
-
markStateDataAsProcessedByCallback({ stateUrlParamValue });
|
|
163
|
-
clearBackForwardTracker();
|
|
164
|
-
writeRedirectAuthResponses({
|
|
165
|
-
authResponses: [...readRedirectAuthResponses(), authResponse]
|
|
166
|
-
});
|
|
167
|
-
reloadOnBfCacheNavigation();
|
|
168
|
-
setTimeout(() => {
|
|
169
|
-
const href = (() => {
|
|
170
|
-
if (stateData.action === "login" && authResponse.error === "consent_required") {
|
|
171
|
-
return stateData.redirectUrl_consentRequiredCase;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return stateData.redirectUrl;
|
|
175
|
-
})();
|
|
176
|
-
|
|
177
|
-
location.href = href;
|
|
178
|
-
}, 0);
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return { isHandled };
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const {
|
|
186
|
-
readRedirectAuthResponses,
|
|
187
|
-
writeRedirectAuthResponses,
|
|
188
|
-
moveRedirectAuthResponseFromSessionStorageToMemory
|
|
189
|
-
} = (() => {
|
|
190
|
-
const AUTH_RESPONSES_KEY = "oidc-spa:authResponses";
|
|
191
|
-
|
|
192
|
-
let authResponses_movedToMemoryFromSessionStorage: AuthResponse[] | undefined = undefined;
|
|
193
|
-
|
|
194
|
-
// NOTE: Here we note that we can re-write on session storage some auth response
|
|
195
|
-
// after earlyInit in retrieveRedirectAuthResponseAndStateData
|
|
196
|
-
// In situation where there are more than one client in the same app and we can't use iframe,
|
|
197
|
-
// we can have one client that has to redirect before the response has been dealt with.
|
|
198
|
-
// In most case it won't happen if the init sequence is deterministic but the client
|
|
199
|
-
// can be instantiated at any time really.
|
|
200
|
-
// So the move to memory of the response is fully effective only when theres one client.
|
|
201
|
-
function writeRedirectAuthResponses(params: { authResponses: AuthResponse[] }): void {
|
|
202
|
-
const { authResponses } = params;
|
|
203
|
-
|
|
204
|
-
authResponses_movedToMemoryFromSessionStorage = undefined;
|
|
205
|
-
|
|
206
|
-
if (authResponses.length === 0) {
|
|
207
|
-
sessionStorage.removeItem(AUTH_RESPONSES_KEY);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
sessionStorage.setItem(AUTH_RESPONSES_KEY, JSON.stringify(authResponses));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function readRedirectAuthResponses(): AuthResponse[] {
|
|
214
|
-
if (authResponses_movedToMemoryFromSessionStorage !== undefined) {
|
|
215
|
-
return authResponses_movedToMemoryFromSessionStorage;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const raw = sessionStorage.getItem(AUTH_RESPONSES_KEY);
|
|
219
|
-
|
|
220
|
-
if (raw === null) {
|
|
221
|
-
return [];
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return JSON.parse(raw);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function moveRedirectAuthResponseFromSessionStorageToMemory() {
|
|
228
|
-
const authResponses = readRedirectAuthResponses();
|
|
229
|
-
|
|
230
|
-
writeRedirectAuthResponses({ authResponses: [] });
|
|
231
|
-
|
|
232
|
-
authResponses_movedToMemoryFromSessionStorage = authResponses;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return {
|
|
236
|
-
writeRedirectAuthResponses,
|
|
237
|
-
readRedirectAuthResponses,
|
|
238
|
-
moveRedirectAuthResponseFromSessionStorageToMemory
|
|
239
|
-
};
|
|
240
|
-
})();
|
|
241
|
-
|
|
242
|
-
export { moveRedirectAuthResponseFromSessionStorageToMemory };
|
|
243
|
-
|
|
244
|
-
export function retrieveRedirectAuthResponseAndStateData(params: {
|
|
245
|
-
configId: string;
|
|
246
|
-
}): { authResponse: AuthResponse; stateData: StateData.Redirect } | undefined {
|
|
247
|
-
const { configId } = params;
|
|
248
|
-
|
|
249
|
-
const authResponses = readRedirectAuthResponses();
|
|
250
|
-
|
|
251
|
-
let authResponseAndStateData:
|
|
252
|
-
| { authResponse: AuthResponse; stateData: StateData.Redirect }
|
|
253
|
-
| undefined = undefined;
|
|
254
|
-
|
|
255
|
-
for (const authResponse of [...authResponses]) {
|
|
256
|
-
const stateData = getStateData({ stateUrlParamValue: authResponse.state });
|
|
257
|
-
|
|
258
|
-
if (stateData === undefined) {
|
|
259
|
-
// NOTE: We do not understand how this can happen but it can.
|
|
260
|
-
authResponses.splice(authResponses.indexOf(authResponse), 1);
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
assert(stateData.context === "redirect", "474728");
|
|
265
|
-
|
|
266
|
-
if (stateData.configId !== configId) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
authResponses.splice(authResponses.indexOf(authResponse), 1);
|
|
271
|
-
|
|
272
|
-
authResponseAndStateData = { authResponse, stateData };
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
writeRedirectAuthResponses({ authResponses });
|
|
276
|
-
|
|
277
|
-
return authResponseAndStateData;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function reloadOnBfCacheNavigation() {
|
|
281
|
-
window.addEventListener("pageshow", event => {
|
|
282
|
-
if (!event.persisted) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
location.reload();
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const { writeBackForwardTracker, readBackForwardTracker, clearBackForwardTracker } = (() => {
|
|
290
|
-
const BACK_NAVIGATION_TRACKER_KEY = "oidc-spa:callback-back-forward-tracker";
|
|
291
|
-
|
|
292
|
-
type BackForwardTracker = {
|
|
293
|
-
previousHistoryMethod: "back" | "forward";
|
|
294
|
-
hasExitedCallback: boolean;
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
function writeBackForwardTracker(params: { backForwardTracker: BackForwardTracker }): void {
|
|
298
|
-
const { backForwardTracker } = params;
|
|
299
|
-
|
|
300
|
-
sessionStorage.setItem(BACK_NAVIGATION_TRACKER_KEY, JSON.stringify(backForwardTracker));
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function readBackForwardTracker(): BackForwardTracker | undefined {
|
|
304
|
-
const raw = sessionStorage.getItem(BACK_NAVIGATION_TRACKER_KEY);
|
|
305
|
-
|
|
306
|
-
if (raw === null) {
|
|
307
|
-
return undefined;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return JSON.parse(raw);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function clearBackForwardTracker(): void {
|
|
314
|
-
sessionStorage.removeItem(BACK_NAVIGATION_TRACKER_KEY);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return { writeBackForwardTracker, readBackForwardTracker, clearBackForwardTracker };
|
|
318
|
-
})();
|