oidc-spa 7.2.0 → 7.2.2
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/backend.js.map +1 -1
- package/core/AuthResponse.js.map +1 -1
- package/core/Oidc.js.map +1 -1
- package/core/OidcInitializationError.js.map +1 -1
- package/core/OidcMetadata.js.map +1 -1
- package/core/StateData.js.map +1 -1
- package/core/configId.js.map +1 -1
- package/core/createOidc.js +1 -1
- package/core/createOidc.js.map +1 -1
- package/core/diagnostic.js.map +1 -1
- package/core/evtIsUserActive.js.map +1 -1
- package/core/handleOidcCallback.js.map +1 -1
- package/core/iframeMessageProtection.js.map +1 -1
- package/core/index.js.map +1 -1
- package/core/initialLocationHref.js.map +1 -1
- package/core/isNewBrowserSession.js.map +1 -1
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/core/loginPropagationToOtherTabs.js.map +1 -1
- package/core/loginSilent.js.map +1 -1
- package/core/logoutPropagationToOtherTabs.js.map +1 -1
- package/core/oidcClientTsUserToTokens.js.map +1 -1
- package/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
- package/core/persistedAuthState.js.map +1 -1
- package/entrypoint.js.map +1 -1
- package/esm/core/AuthResponse.js +2 -2
- package/esm/core/AuthResponse.js.map +1 -1
- package/esm/core/Oidc.d.ts +1 -1
- package/esm/core/Oidc.js.map +1 -1
- package/esm/core/OidcInitializationError.js.map +1 -1
- package/esm/core/OidcMetadata.js +2 -2
- package/esm/core/OidcMetadata.js.map +1 -1
- package/esm/core/StateData.js +3 -3
- package/esm/core/StateData.js.map +1 -1
- package/esm/core/configId.js.map +1 -1
- package/esm/core/createOidc.d.ts +2 -2
- package/esm/core/createOidc.js +33 -33
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/diagnostic.d.ts +1 -1
- package/esm/core/diagnostic.js +4 -4
- package/esm/core/diagnostic.js.map +1 -1
- package/esm/core/evtIsUserActive.d.ts +1 -1
- package/esm/core/evtIsUserActive.js +5 -5
- package/esm/core/evtIsUserActive.js.map +1 -1
- package/esm/core/handleOidcCallback.d.ts +2 -2
- package/esm/core/handleOidcCallback.js +5 -5
- package/esm/core/handleOidcCallback.js.map +1 -1
- package/esm/core/iframeMessageProtection.d.ts +1 -1
- package/esm/core/iframeMessageProtection.js +3 -3
- package/esm/core/iframeMessageProtection.js.map +1 -1
- package/esm/core/index.d.ts +4 -4
- package/esm/core/index.js +4 -4
- package/esm/core/index.js.map +1 -1
- package/esm/core/initialLocationHref.js.map +1 -1
- package/esm/core/isNewBrowserSession.d.ts +1 -1
- package/esm/core/isNewBrowserSession.js.map +1 -1
- package/esm/core/loginOrGoToAuthServer.d.ts +2 -2
- package/esm/core/loginOrGoToAuthServer.js +6 -6
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/core/loginPropagationToOtherTabs.js +3 -3
- package/esm/core/loginPropagationToOtherTabs.js.map +1 -1
- package/esm/core/loginSilent.d.ts +2 -2
- package/esm/core/loginSilent.js +8 -8
- package/esm/core/loginSilent.js.map +1 -1
- package/esm/core/logoutPropagationToOtherTabs.js +3 -3
- package/esm/core/logoutPropagationToOtherTabs.js.map +1 -1
- package/esm/core/oidcClientTsUserToTokens.d.ts +2 -2
- package/esm/core/oidcClientTsUserToTokens.js +4 -4
- package/esm/core/oidcClientTsUserToTokens.js.map +1 -1
- package/esm/core/ongoingLoginOrRefreshProcesses.js +3 -3
- package/esm/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
- package/esm/core/persistedAuthState.js +2 -2
- package/esm/core/persistedAuthState.js.map +1 -1
- package/esm/entrypoint.js +3 -3
- package/esm/entrypoint.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.js +2 -2
- package/esm/index.js.map +1 -1
- package/esm/keycloak/index.d.ts +3 -3
- package/esm/keycloak/index.js +3 -3
- package/esm/keycloak/index.js.map +1 -1
- package/esm/keycloak/isKeycloak.js.map +1 -1
- package/esm/keycloak/keycloak-js/Keycloak.d.ts +1 -1
- package/esm/keycloak/keycloak-js/Keycloak.js +9 -9
- package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/esm/keycloak/keycloak-js/index.d.ts +2 -2
- package/esm/keycloak/keycloak-js/index.js +2 -2
- package/esm/keycloak/keycloak-js/index.js.map +1 -1
- package/esm/keycloak/keycloak-js/types.js.map +1 -1
- package/esm/keycloak/keycloakIssuerUriParsed.js +3 -3
- package/esm/keycloak/keycloakIssuerUriParsed.js.map +1 -1
- package/esm/keycloak/keycloakUtils.d.ts +1 -1
- package/esm/keycloak/keycloakUtils.js +3 -3
- package/esm/keycloak/keycloakUtils.js.map +1 -1
- package/esm/keycloak-js.d.ts +1 -1
- package/esm/keycloak-js.js +2 -2
- package/esm/keycloak-js.js.map +1 -1
- package/esm/mock/index.d.ts +1 -1
- package/esm/mock/index.js +2 -2
- package/esm/mock/index.js.map +1 -1
- package/esm/mock/oidc.d.ts +1 -1
- package/esm/mock/oidc.js +6 -6
- package/esm/mock/oidc.js.map +1 -1
- package/esm/mock/react.d.ts +8 -8
- package/esm/mock/react.js +3 -3
- package/esm/mock/react.js.map +1 -1
- package/esm/react/index.d.ts +1 -1
- package/esm/react/index.js +2 -2
- package/esm/react/index.js.map +1 -1
- package/esm/react/react.d.ts +2 -2
- package/esm/react/react.js +6 -6
- package/esm/react/react.js.map +1 -1
- package/esm/tools/Deferred.js.map +1 -1
- package/esm/tools/EphemeralSessionStorage.js +2 -2
- package/esm/tools/EphemeralSessionStorage.js.map +1 -1
- package/esm/tools/Evt.js +3 -3
- package/esm/tools/Evt.js.map +1 -1
- package/esm/tools/StatefulEvt.js.map +1 -1
- package/esm/tools/ValueOrAsyncGetter.js.map +1 -1
- package/esm/tools/asymmetricEncryption.js.map +1 -1
- package/esm/tools/base64.js.map +1 -1
- package/esm/tools/createObjectThatThrowsIfAccessed.js.map +1 -1
- package/esm/tools/decodeJwt.js.map +1 -1
- package/esm/tools/generateUrlSafeRandom.js.map +1 -1
- package/esm/tools/getDownlinkAndRtt.js +2 -2
- package/esm/tools/getDownlinkAndRtt.js.map +1 -1
- package/esm/tools/getIsOnline.js +2 -2
- package/esm/tools/getIsOnline.js.map +1 -1
- package/esm/tools/getIsValidRemoteJson.js.map +1 -1
- package/esm/tools/getPrUserInteraction.js +2 -2
- package/esm/tools/getPrUserInteraction.js.map +1 -1
- package/esm/tools/getUserEnvironmentInfo.js.map +1 -1
- package/esm/tools/haveSharedParentDomain.js.map +1 -1
- package/esm/tools/isDev.js.map +1 -1
- package/esm/tools/parseKeycloakIssuerUri.js +2 -2
- package/esm/tools/parseKeycloakIssuerUri.js.map +1 -1
- package/esm/tools/readExpirationTimeInJwt.js +3 -3
- package/esm/tools/readExpirationTimeInJwt.js.map +1 -1
- package/esm/tools/startCountdown.js +2 -2
- package/esm/tools/startCountdown.js.map +1 -1
- package/esm/tools/subscribeToUserInteraction.js +2 -2
- package/esm/tools/subscribeToUserInteraction.js.map +1 -1
- package/esm/tools/toFullyQualifiedUrl.js.map +1 -1
- package/esm/tools/toHumanReadableDuration.js.map +1 -1
- package/esm/tools/urlSearchParams.js.map +1 -1
- package/esm/tools/workerTimers.js +2 -2
- package/esm/tools/workerTimers.js.map +1 -1
- package/index.js.map +1 -1
- package/keycloak/index.js.map +1 -1
- package/keycloak/isKeycloak.js.map +1 -1
- package/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/keycloak/keycloak-js/index.js.map +1 -1
- package/keycloak/keycloak-js/types.js.map +1 -1
- package/keycloak/keycloakIssuerUriParsed.js.map +1 -1
- package/keycloak/keycloakUtils.js.map +1 -1
- package/keycloak-js.js.map +1 -1
- package/mock/index.js.map +1 -1
- package/mock/oidc.js.map +1 -1
- package/mock/react.js.map +1 -1
- package/package.json +1 -1
- package/react/index.js.map +1 -1
- package/react/react.js.map +1 -1
- package/src/backend.ts +391 -0
- package/src/core/AuthResponse.ts +26 -0
- package/src/core/Oidc.ts +140 -0
- package/src/core/OidcInitializationError.ts +19 -0
- package/src/core/OidcMetadata.ts +271 -0
- package/src/core/StateData.ts +118 -0
- package/src/core/configId.ts +3 -0
- package/src/core/createOidc.ts +1576 -0
- package/src/core/diagnostic.ts +267 -0
- package/src/core/evtIsUserActive.ts +108 -0
- package/src/core/handleOidcCallback.ts +321 -0
- package/src/core/iframeMessageProtection.ts +100 -0
- package/src/core/index.ts +4 -0
- package/src/core/initialLocationHref.ts +5 -0
- package/src/core/isNewBrowserSession.ts +37 -0
- package/src/core/loginOrGoToAuthServer.ts +324 -0
- package/src/core/loginPropagationToOtherTabs.ts +51 -0
- package/src/core/loginSilent.ts +242 -0
- package/src/core/logoutPropagationToOtherTabs.ts +53 -0
- package/src/core/oidcClientTsUserToTokens.ts +229 -0
- package/src/core/ongoingLoginOrRefreshProcesses.ts +47 -0
- package/src/core/persistedAuthState.ts +122 -0
- package/src/entrypoint.ts +69 -0
- package/src/index.ts +1 -0
- package/src/keycloak/index.ts +8 -0
- package/src/keycloak/isKeycloak.ts +23 -0
- package/src/keycloak/keycloak-js/Keycloak.ts +1097 -0
- package/src/keycloak/keycloak-js/index.ts +2 -0
- package/src/keycloak/keycloak-js/types.ts +442 -0
- package/src/keycloak/keycloakIssuerUriParsed.ts +29 -0
- package/src/keycloak/keycloakUtils.ts +90 -0
- package/src/keycloak-js.ts +1 -0
- package/src/mock/index.ts +1 -0
- package/src/mock/oidc.ts +211 -0
- package/src/mock/react.tsx +11 -0
- package/src/react/index.ts +1 -0
- package/src/react/react.tsx +476 -0
- package/src/tools/Deferred.ts +33 -0
- package/src/tools/EphemeralSessionStorage.ts +223 -0
- package/src/tools/Evt.ts +56 -0
- package/src/tools/StatefulEvt.ts +38 -0
- package/src/tools/ValueOrAsyncGetter.ts +1 -0
- package/src/tools/asymmetricEncryption.ts +184 -0
- package/src/tools/base64.ts +7 -0
- package/src/tools/createObjectThatThrowsIfAccessed.ts +40 -0
- package/src/tools/decodeJwt.ts +95 -0
- package/src/tools/generateUrlSafeRandom.ts +26 -0
- package/src/tools/getDownlinkAndRtt.ts +22 -0
- package/src/tools/getIsOnline.ts +20 -0
- package/src/tools/getIsValidRemoteJson.ts +18 -0
- package/src/tools/getPrUserInteraction.ts +27 -0
- package/src/tools/getUserEnvironmentInfo.ts +42 -0
- package/src/tools/haveSharedParentDomain.ts +13 -0
- package/src/tools/isDev.ts +30 -0
- package/src/tools/parseKeycloakIssuerUri.ts +49 -0
- package/src/tools/readExpirationTimeInJwt.ts +16 -0
- package/src/tools/startCountdown.ts +36 -0
- package/src/tools/subscribeToUserInteraction.ts +33 -0
- package/src/tools/toFullyQualifiedUrl.ts +58 -0
- package/src/tools/toHumanReadableDuration.ts +21 -0
- package/src/tools/urlSearchParams.ts +130 -0
- package/src/tools/workerTimers.ts +57 -0
- package/src/vendor/backend/evt.ts +2 -0
- package/src/vendor/backend/jsonwebtoken.ts +1 -0
- package/src/vendor/backend/node-fetch.ts +2 -0
- package/src/vendor/backend/node-jose.ts +1 -0
- package/src/vendor/backend/tsafe.ts +5 -0
- package/src/vendor/backend/zod.ts +1 -0
- package/src/vendor/frontend/oidc-client-ts.ts +1 -0
- package/src/vendor/frontend/tsafe.ts +6 -0
- package/src/vendor/frontend/worker-timers.ts +2 -0
- package/tools/Deferred.js.map +1 -1
- package/tools/EphemeralSessionStorage.js.map +1 -1
- package/tools/Evt.js.map +1 -1
- package/tools/StatefulEvt.js.map +1 -1
- package/tools/ValueOrAsyncGetter.js.map +1 -1
- package/tools/asymmetricEncryption.js.map +1 -1
- package/tools/base64.js.map +1 -1
- package/tools/createObjectThatThrowsIfAccessed.js.map +1 -1
- package/tools/decodeJwt.js.map +1 -1
- package/tools/generateUrlSafeRandom.js.map +1 -1
- package/tools/getDownlinkAndRtt.js.map +1 -1
- package/tools/getIsOnline.js.map +1 -1
- package/tools/getIsValidRemoteJson.js.map +1 -1
- package/tools/getPrUserInteraction.js.map +1 -1
- package/tools/getUserEnvironmentInfo.js.map +1 -1
- package/tools/haveSharedParentDomain.js.map +1 -1
- package/tools/isDev.js.map +1 -1
- package/tools/parseKeycloakIssuerUri.js.map +1 -1
- package/tools/readExpirationTimeInJwt.js.map +1 -1
- package/tools/startCountdown.js.map +1 -1
- package/tools/subscribeToUserInteraction.js.map +1 -1
- package/tools/toFullyQualifiedUrl.js.map +1 -1
- package/tools/toHumanReadableDuration.js.map +1 -1
- package/tools/urlSearchParams.js.map +1 -1
- package/tools/workerTimers.js.map +1 -1
package/src/mock/oidc.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { Oidc } from "../core";
|
|
2
|
+
import { createObjectThatThrowsIfAccessed } from "../tools/createObjectThatThrowsIfAccessed";
|
|
3
|
+
import { id } from "../vendor/frontend/tsafe";
|
|
4
|
+
import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
|
|
5
|
+
import { getSearchParam, addOrUpdateSearchParam } from "../tools/urlSearchParams";
|
|
6
|
+
import { initialLocationHref } from "../core/initialLocationHref";
|
|
7
|
+
|
|
8
|
+
export type ParamsOfCreateMockOidc<
|
|
9
|
+
DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
|
|
10
|
+
AutoLogin extends boolean = false
|
|
11
|
+
> = {
|
|
12
|
+
mockedParams?: Partial<Oidc["params"]>;
|
|
13
|
+
mockedTokens?: Partial<Oidc.Tokens<DecodedIdToken>>;
|
|
14
|
+
/**
|
|
15
|
+
* The URL of the home page of your app.
|
|
16
|
+
* We need to know this so we know where to redirect when you call `logout({ redirectTo: "home"})`.
|
|
17
|
+
* In the majority of cases it should be `homeUrl: "/"` but it could aso be something like `homeUrl: "/dashboard"`
|
|
18
|
+
* if your web app isn't hosted at the root of the domain.
|
|
19
|
+
*/
|
|
20
|
+
homeUrl: string;
|
|
21
|
+
autoLogin?: AutoLogin;
|
|
22
|
+
postLoginRedirectUrl?: string;
|
|
23
|
+
} & (AutoLogin extends true
|
|
24
|
+
? { isUserInitiallyLoggedIn?: true }
|
|
25
|
+
: {
|
|
26
|
+
isUserInitiallyLoggedIn: boolean;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const URL_SEARCH_PARAM_NAME = "isUserLoggedIn";
|
|
30
|
+
|
|
31
|
+
export async function createMockOidc<
|
|
32
|
+
DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_base,
|
|
33
|
+
AutoLogin extends boolean = false
|
|
34
|
+
>(
|
|
35
|
+
params: ParamsOfCreateMockOidc<DecodedIdToken, AutoLogin>
|
|
36
|
+
): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
|
|
37
|
+
const {
|
|
38
|
+
isUserInitiallyLoggedIn = true,
|
|
39
|
+
mockedParams = {},
|
|
40
|
+
mockedTokens = {},
|
|
41
|
+
homeUrl: homeUrl_params,
|
|
42
|
+
autoLogin = false,
|
|
43
|
+
postLoginRedirectUrl
|
|
44
|
+
} = params;
|
|
45
|
+
|
|
46
|
+
const isUserLoggedIn = (() => {
|
|
47
|
+
const { wasPresent, value } = getSearchParam({
|
|
48
|
+
url: initialLocationHref,
|
|
49
|
+
name: URL_SEARCH_PARAM_NAME
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!wasPresent) {
|
|
53
|
+
return isUserInitiallyLoggedIn;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
remove_from_url: {
|
|
57
|
+
const { wasPresent, url_withoutTheParam } = getSearchParam({
|
|
58
|
+
url: window.location.href,
|
|
59
|
+
name: URL_SEARCH_PARAM_NAME
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (!wasPresent) {
|
|
63
|
+
break remove_from_url;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
window.history.replaceState({}, "", url_withoutTheParam);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return value === "true";
|
|
70
|
+
})();
|
|
71
|
+
|
|
72
|
+
const homeUrl = toFullyQualifiedUrl({
|
|
73
|
+
urlish: homeUrl_params,
|
|
74
|
+
doAssertNoQueryParams: true,
|
|
75
|
+
doOutputWithTrailingSlash: true
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const common: Oidc.Common = {
|
|
79
|
+
params: {
|
|
80
|
+
clientId: mockedParams.clientId ?? "mymockclient",
|
|
81
|
+
issuerUri: mockedParams.issuerUri ?? "https://my-mock-oidc-server.net/realms/mymockrealm"
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const loginOrGoToAuthServer = async (params: {
|
|
86
|
+
redirectUrl: string | undefined;
|
|
87
|
+
}): Promise<never> => {
|
|
88
|
+
const { redirectUrl: redirectUrl_params } = params;
|
|
89
|
+
|
|
90
|
+
const redirectUrl = addOrUpdateSearchParam({
|
|
91
|
+
url: (() => {
|
|
92
|
+
if (redirectUrl_params === undefined) {
|
|
93
|
+
return window.location.href;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return toFullyQualifiedUrl({
|
|
97
|
+
urlish: redirectUrl_params,
|
|
98
|
+
doAssertNoQueryParams: false
|
|
99
|
+
});
|
|
100
|
+
})(),
|
|
101
|
+
name: URL_SEARCH_PARAM_NAME,
|
|
102
|
+
value: "true",
|
|
103
|
+
encodeMethod: "www-form"
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
window.location.href = redirectUrl;
|
|
107
|
+
|
|
108
|
+
return new Promise<never>(() => {});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (!isUserLoggedIn) {
|
|
112
|
+
const oidc = id<Oidc.NotLoggedIn>({
|
|
113
|
+
...common,
|
|
114
|
+
isUserLoggedIn: false,
|
|
115
|
+
login: ({ redirectUrl }) => loginOrGoToAuthServer({ redirectUrl }),
|
|
116
|
+
initializationError: undefined
|
|
117
|
+
});
|
|
118
|
+
if (autoLogin) {
|
|
119
|
+
await oidc.login({
|
|
120
|
+
redirectUrl: postLoginRedirectUrl,
|
|
121
|
+
doesCurrentHrefRequiresAuth: true
|
|
122
|
+
});
|
|
123
|
+
// Never here
|
|
124
|
+
}
|
|
125
|
+
// @ts-expect-error: We know what we are doing
|
|
126
|
+
return oidc;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const oidc: Oidc.LoggedIn<DecodedIdToken> = {
|
|
130
|
+
...common,
|
|
131
|
+
isUserLoggedIn: true,
|
|
132
|
+
renewTokens: async () => {},
|
|
133
|
+
...(() => {
|
|
134
|
+
const tokens_common: Oidc.Tokens.Common<DecodedIdToken> = {
|
|
135
|
+
accessToken: mockedTokens.accessToken ?? "mocked-access-token",
|
|
136
|
+
accessTokenExpirationTime: mockedTokens.accessTokenExpirationTime ?? Infinity,
|
|
137
|
+
idToken: mockedTokens.idToken ?? "mocked-id-token",
|
|
138
|
+
decodedIdToken:
|
|
139
|
+
mockedTokens.decodedIdToken ??
|
|
140
|
+
createObjectThatThrowsIfAccessed<DecodedIdToken>({
|
|
141
|
+
debugMessage: [
|
|
142
|
+
"You haven't provided a mocked decodedIdToken",
|
|
143
|
+
"See https://docs.oidc-spa.dev/v/v7/mock"
|
|
144
|
+
].join("\n")
|
|
145
|
+
}),
|
|
146
|
+
decodedIdToken_original:
|
|
147
|
+
mockedTokens.decodedIdToken_original ??
|
|
148
|
+
createObjectThatThrowsIfAccessed<Oidc.Tokens.DecodedIdToken_base>({
|
|
149
|
+
debugMessage: [
|
|
150
|
+
"You haven't provided a mocked decodedIdToken_original",
|
|
151
|
+
"See https://docs.oidc-spa.dev/v/v7/mock"
|
|
152
|
+
].join("\n")
|
|
153
|
+
}),
|
|
154
|
+
issuedAtTime: Date.now()
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const tokens: Oidc.Tokens<DecodedIdToken> =
|
|
158
|
+
mockedTokens.refreshToken !== undefined || mockedTokens.hasRefreshToken === true
|
|
159
|
+
? id<Oidc.Tokens.WithRefreshToken<DecodedIdToken>>({
|
|
160
|
+
...tokens_common,
|
|
161
|
+
hasRefreshToken: true,
|
|
162
|
+
refreshToken: mockedTokens.refreshToken ?? "mocked-refresh-token",
|
|
163
|
+
refreshTokenExpirationTime: mockedTokens.refreshTokenExpirationTime
|
|
164
|
+
})
|
|
165
|
+
: id<Oidc.Tokens.WithoutRefreshToken<DecodedIdToken>>({
|
|
166
|
+
...tokens_common,
|
|
167
|
+
hasRefreshToken: false
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
getTokens: () => Promise.resolve(tokens),
|
|
172
|
+
getDecodedIdToken: () => tokens_common.decodedIdToken
|
|
173
|
+
};
|
|
174
|
+
})(),
|
|
175
|
+
subscribeToTokensChange: () => ({
|
|
176
|
+
unsubscribe: () => {}
|
|
177
|
+
}),
|
|
178
|
+
logout: params => {
|
|
179
|
+
const redirectUrl = addOrUpdateSearchParam({
|
|
180
|
+
url: (() => {
|
|
181
|
+
switch (params.redirectTo) {
|
|
182
|
+
case "current page":
|
|
183
|
+
return window.location.href;
|
|
184
|
+
case "home":
|
|
185
|
+
return homeUrl;
|
|
186
|
+
case "specific url":
|
|
187
|
+
return toFullyQualifiedUrl({
|
|
188
|
+
urlish: params.url,
|
|
189
|
+
doAssertNoQueryParams: false
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
})(),
|
|
193
|
+
name: URL_SEARCH_PARAM_NAME,
|
|
194
|
+
value: "false",
|
|
195
|
+
encodeMethod: "www-form"
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
window.location.href = redirectUrl;
|
|
199
|
+
|
|
200
|
+
return new Promise<never>(() => {});
|
|
201
|
+
},
|
|
202
|
+
subscribeToAutoLogoutCountdown: () => ({
|
|
203
|
+
unsubscribeFromAutoLogoutCountdown: () => {}
|
|
204
|
+
}),
|
|
205
|
+
goToAuthServer: async ({ redirectUrl }) => loginOrGoToAuthServer({ redirectUrl }),
|
|
206
|
+
isNewBrowserSession: false,
|
|
207
|
+
backFromAuthServer: undefined
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
return oidc;
|
|
211
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createOidcReactApi_dependencyInjection } from "../react/react";
|
|
2
|
+
import { createMockOidc, type ParamsOfCreateMockOidc } from "./oidc";
|
|
3
|
+
import type { ValueOrAsyncGetter } from "../tools/ValueOrAsyncGetter";
|
|
4
|
+
|
|
5
|
+
/** @see: https://docs.oidc-spa.dev/v/v7/mock */
|
|
6
|
+
export function createMockReactOidc<
|
|
7
|
+
DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
|
|
8
|
+
AutoLogin extends boolean = false
|
|
9
|
+
>(params: ValueOrAsyncGetter<ParamsOfCreateMockOidc<DecodedIdToken, AutoLogin>>) {
|
|
10
|
+
return createOidcReactApi_dependencyInjection(params, createMockOidc);
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type OidcReact, createReactOidc } from "./react";
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useEffect,
|
|
3
|
+
useState,
|
|
4
|
+
createContext,
|
|
5
|
+
useContext,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
type ComponentType,
|
|
8
|
+
type FC,
|
|
9
|
+
type JSX
|
|
10
|
+
} from "react";
|
|
11
|
+
import {
|
|
12
|
+
type Oidc,
|
|
13
|
+
createOidc,
|
|
14
|
+
type ParamsOfCreateOidc,
|
|
15
|
+
OidcInitializationError,
|
|
16
|
+
handleOidcCallback
|
|
17
|
+
} from "../core";
|
|
18
|
+
import { assert, type Equals, type Param0 } from "../vendor/frontend/tsafe";
|
|
19
|
+
import { id } from "../vendor/frontend/tsafe";
|
|
20
|
+
import type { ValueOrAsyncGetter } from "../tools/ValueOrAsyncGetter";
|
|
21
|
+
import { Deferred } from "../tools/Deferred";
|
|
22
|
+
import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
|
|
23
|
+
|
|
24
|
+
export type OidcReact<DecodedIdToken extends Record<string, unknown>> =
|
|
25
|
+
| OidcReact.NotLoggedIn
|
|
26
|
+
| OidcReact.LoggedIn<DecodedIdToken>;
|
|
27
|
+
|
|
28
|
+
export namespace OidcReact {
|
|
29
|
+
export type Common = Oidc.Common & {
|
|
30
|
+
useAutoLogoutWarningCountdown: (params: { warningDurationSeconds: number }) => {
|
|
31
|
+
secondsLeft: number | undefined;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type NotLoggedIn = Common & {
|
|
36
|
+
isUserLoggedIn: false;
|
|
37
|
+
login: (params?: {
|
|
38
|
+
extraQueryParams?: Record<string, string | undefined>;
|
|
39
|
+
redirectUrl?: string;
|
|
40
|
+
transformUrlBeforeRedirect?: (url: string) => string;
|
|
41
|
+
doesCurrentHrefRequiresAuth?: boolean;
|
|
42
|
+
}) => Promise<never>;
|
|
43
|
+
initializationError: OidcInitializationError | undefined;
|
|
44
|
+
|
|
45
|
+
decodedIdToken?: never;
|
|
46
|
+
logout?: never;
|
|
47
|
+
renewTokens?: never;
|
|
48
|
+
goToAuthServer?: never;
|
|
49
|
+
backFromAuthServer?: never;
|
|
50
|
+
isNewBrowserSession?: never;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type LoggedIn<DecodedIdToken extends Record<string, unknown>> = Common & {
|
|
54
|
+
isUserLoggedIn: true;
|
|
55
|
+
decodedIdToken: DecodedIdToken;
|
|
56
|
+
logout: Oidc.LoggedIn["logout"];
|
|
57
|
+
renewTokens: Oidc.LoggedIn["renewTokens"];
|
|
58
|
+
login?: never;
|
|
59
|
+
initializationError?: never;
|
|
60
|
+
goToAuthServer: (params: {
|
|
61
|
+
extraQueryParams?: Record<string, string>;
|
|
62
|
+
redirectUrl?: string;
|
|
63
|
+
transformUrlBeforeRedirect?: (url: string) => string;
|
|
64
|
+
}) => Promise<never>;
|
|
65
|
+
|
|
66
|
+
backFromAuthServer:
|
|
67
|
+
| {
|
|
68
|
+
extraQueryParams: Record<string, string>;
|
|
69
|
+
result: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
| undefined;
|
|
72
|
+
|
|
73
|
+
isNewBrowserSession: boolean;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
{
|
|
77
|
+
type Actual = Param0<OidcReact.NotLoggedIn["login"]>;
|
|
78
|
+
type Expected = Omit<Param0<Oidc.NotLoggedIn["login"]>, "doesCurrentHrefRequiresAuth"> & {
|
|
79
|
+
doesCurrentHrefRequiresAuth?: boolean;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
assert<Equals<Actual, Expected>>();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type OidcReactApi<DecodedIdToken extends Record<string, unknown>, AutoLogin extends boolean> = {
|
|
86
|
+
OidcProvider: AutoLogin extends true
|
|
87
|
+
? (props: {
|
|
88
|
+
fallback?: ReactNode;
|
|
89
|
+
ErrorFallback?: (props: { initializationError: OidcInitializationError }) => ReactNode;
|
|
90
|
+
children: ReactNode;
|
|
91
|
+
}) => JSX.Element
|
|
92
|
+
: (props: { fallback?: ReactNode; children: ReactNode }) => JSX.Element;
|
|
93
|
+
useOidc: AutoLogin extends true
|
|
94
|
+
? {
|
|
95
|
+
(params?: { assert: "user logged in" }): OidcReact.LoggedIn<DecodedIdToken>;
|
|
96
|
+
}
|
|
97
|
+
: {
|
|
98
|
+
(params?: { assert?: undefined }): OidcReact<DecodedIdToken>;
|
|
99
|
+
(params: { assert: "user logged in" }): OidcReact.LoggedIn<DecodedIdToken>;
|
|
100
|
+
(params: { assert: "user not logged in" }): OidcReact.NotLoggedIn;
|
|
101
|
+
};
|
|
102
|
+
getOidc: () => Promise<
|
|
103
|
+
AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>
|
|
104
|
+
>;
|
|
105
|
+
} & (AutoLogin extends true
|
|
106
|
+
? {}
|
|
107
|
+
: {
|
|
108
|
+
withLoginEnforced: <Props extends Record<string, unknown>>(
|
|
109
|
+
Component: ComponentType<Props>,
|
|
110
|
+
params?: {
|
|
111
|
+
onRedirecting: () => JSX.Element | null;
|
|
112
|
+
}
|
|
113
|
+
) => FC<Props>;
|
|
114
|
+
enforceLogin: (loaderParams: {
|
|
115
|
+
request?: { url?: string };
|
|
116
|
+
cause?: "preload" | string;
|
|
117
|
+
location?: {
|
|
118
|
+
href?: string;
|
|
119
|
+
};
|
|
120
|
+
}) => Promise<void | never>;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export function createOidcReactApi_dependencyInjection<
|
|
124
|
+
DecodedIdToken extends Record<string, unknown>,
|
|
125
|
+
ParamsOfCreateOidc extends {
|
|
126
|
+
autoLogin?: boolean;
|
|
127
|
+
} & (
|
|
128
|
+
| {
|
|
129
|
+
decodedIdTokenSchema: { parse: (data: unknown) => DecodedIdToken } | undefined;
|
|
130
|
+
}
|
|
131
|
+
| {}
|
|
132
|
+
)
|
|
133
|
+
>(
|
|
134
|
+
paramsOrGetParams: ValueOrAsyncGetter<ParamsOfCreateOidc>,
|
|
135
|
+
createOidc: (params: ParamsOfCreateOidc) => Promise<Oidc<DecodedIdToken>>
|
|
136
|
+
): OidcReactApi<
|
|
137
|
+
DecodedIdToken,
|
|
138
|
+
ParamsOfCreateOidc extends { autoLogin?: true | undefined } ? true : false
|
|
139
|
+
> {
|
|
140
|
+
const dReadyToCreate = new Deferred<void>();
|
|
141
|
+
|
|
142
|
+
const oidcContext = createContext<{ oidc: Oidc<DecodedIdToken>; fallback: ReactNode } | undefined>(
|
|
143
|
+
undefined
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// NOTE: It can be InitializationError only if autoLogin is true
|
|
147
|
+
const prOidcOrInitializationError = (async () => {
|
|
148
|
+
// We're doing this here just for people that wouldn't have
|
|
149
|
+
// configured the early init in entrypoint.
|
|
150
|
+
{
|
|
151
|
+
const { isHandled } = handleOidcCallback();
|
|
152
|
+
|
|
153
|
+
if (isHandled) {
|
|
154
|
+
return new Promise<never>(() => {});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const params = await (async () => {
|
|
159
|
+
if (typeof paramsOrGetParams === "function") {
|
|
160
|
+
const getParams = paramsOrGetParams;
|
|
161
|
+
|
|
162
|
+
await dReadyToCreate.pr;
|
|
163
|
+
|
|
164
|
+
const params = await getParams();
|
|
165
|
+
|
|
166
|
+
return params;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const params = paramsOrGetParams;
|
|
170
|
+
|
|
171
|
+
return params;
|
|
172
|
+
})();
|
|
173
|
+
|
|
174
|
+
let oidc: Oidc<DecodedIdToken>;
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
oidc = await createOidc(params);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (!(error instanceof OidcInitializationError)) {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return error;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return oidc;
|
|
187
|
+
})();
|
|
188
|
+
|
|
189
|
+
let prOidcOrInitializationError_resolvedValue:
|
|
190
|
+
| Oidc<DecodedIdToken>
|
|
191
|
+
| OidcInitializationError
|
|
192
|
+
| undefined = undefined;
|
|
193
|
+
prOidcOrInitializationError.then(value => (prOidcOrInitializationError_resolvedValue = value));
|
|
194
|
+
|
|
195
|
+
function OidcProvider(props: {
|
|
196
|
+
fallback?: ReactNode;
|
|
197
|
+
ErrorFallback?: (props: { initializationError: OidcInitializationError }) => ReactNode;
|
|
198
|
+
children: ReactNode;
|
|
199
|
+
}) {
|
|
200
|
+
const { fallback, ErrorFallback, children } = props;
|
|
201
|
+
|
|
202
|
+
const [oidcOrInitializationError, setOidcOrInitializationError] = useState<
|
|
203
|
+
Oidc<DecodedIdToken> | OidcInitializationError | undefined
|
|
204
|
+
>(prOidcOrInitializationError_resolvedValue);
|
|
205
|
+
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (oidcOrInitializationError !== undefined) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
dReadyToCreate.resolve();
|
|
212
|
+
prOidcOrInitializationError.then(setOidcOrInitializationError);
|
|
213
|
+
}, []);
|
|
214
|
+
|
|
215
|
+
if (oidcOrInitializationError === undefined) {
|
|
216
|
+
return <>{fallback === undefined ? null : fallback}</>;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (oidcOrInitializationError instanceof OidcInitializationError) {
|
|
220
|
+
const initializationError = oidcOrInitializationError;
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<>
|
|
224
|
+
{ErrorFallback === undefined ? (
|
|
225
|
+
<h1 style={{ color: "red" }}>
|
|
226
|
+
An error occurred while initializing the OIDC client:
|
|
227
|
+
{initializationError.message}
|
|
228
|
+
</h1>
|
|
229
|
+
) : (
|
|
230
|
+
<ErrorFallback initializationError={initializationError} />
|
|
231
|
+
)}
|
|
232
|
+
</>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const oidc = oidcOrInitializationError;
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<oidcContext.Provider value={{ oidc, fallback: fallback ?? null }}>
|
|
240
|
+
{children}
|
|
241
|
+
</oidcContext.Provider>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const useAutoLogoutWarningCountdown: OidcReact.LoggedIn<DecodedIdToken>["useAutoLogoutWarningCountdown"] =
|
|
246
|
+
({ warningDurationSeconds }) => {
|
|
247
|
+
const contextValue = useContext(oidcContext);
|
|
248
|
+
|
|
249
|
+
assert(contextValue !== undefined);
|
|
250
|
+
|
|
251
|
+
const { oidc } = contextValue;
|
|
252
|
+
|
|
253
|
+
const [secondsLeft, setSecondsLeft] = useState<number | undefined>(undefined);
|
|
254
|
+
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!oidc.isUserLoggedIn) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const { unsubscribeFromAutoLogoutCountdown } = oidc.subscribeToAutoLogoutCountdown(
|
|
261
|
+
({ secondsLeft }) =>
|
|
262
|
+
setSecondsLeft(
|
|
263
|
+
secondsLeft === undefined || secondsLeft > warningDurationSeconds
|
|
264
|
+
? undefined
|
|
265
|
+
: secondsLeft
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
return () => {
|
|
270
|
+
unsubscribeFromAutoLogoutCountdown();
|
|
271
|
+
};
|
|
272
|
+
}, [warningDurationSeconds]);
|
|
273
|
+
|
|
274
|
+
return { secondsLeft };
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
function useOidc(params?: {
|
|
278
|
+
assert?: "user logged in" | "user not logged in";
|
|
279
|
+
}): OidcReact<DecodedIdToken> {
|
|
280
|
+
const { assert: assert_params } = params ?? {};
|
|
281
|
+
|
|
282
|
+
const contextValue = useContext(oidcContext);
|
|
283
|
+
|
|
284
|
+
assert(contextValue !== undefined, "You must use useOidc inside the corresponding OidcProvider");
|
|
285
|
+
|
|
286
|
+
const { oidc } = contextValue;
|
|
287
|
+
|
|
288
|
+
check_assertion: {
|
|
289
|
+
if (assert_params === undefined) {
|
|
290
|
+
break check_assertion;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const getMessage = (v: string) =>
|
|
294
|
+
[
|
|
295
|
+
"There is a logic error in the application.",
|
|
296
|
+
`If this component is mounted the user is supposed ${v}.`,
|
|
297
|
+
"An explicit assertion was made in this sense."
|
|
298
|
+
].join(" ");
|
|
299
|
+
|
|
300
|
+
switch (assert_params) {
|
|
301
|
+
case "user logged in":
|
|
302
|
+
if (!oidc.isUserLoggedIn) {
|
|
303
|
+
throw new Error(getMessage("to be logged in but currently they arn't"));
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
case "user not logged in":
|
|
307
|
+
if (oidc.isUserLoggedIn) {
|
|
308
|
+
throw new Error(getMessage("not to be logged in but currently they are"));
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
default:
|
|
312
|
+
assert<Equals<typeof assert_params, never>>(false);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const [, reRenderIfDecodedIdTokenChanged] = useState(
|
|
317
|
+
!oidc.isUserLoggedIn ? undefined : oidc.getDecodedIdToken()
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
if (!oidc.isUserLoggedIn) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const { unsubscribe } = oidc.subscribeToTokensChange(() =>
|
|
326
|
+
reRenderIfDecodedIdTokenChanged(oidc.getDecodedIdToken())
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
reRenderIfDecodedIdTokenChanged(oidc.getDecodedIdToken());
|
|
330
|
+
|
|
331
|
+
return unsubscribe;
|
|
332
|
+
}, []);
|
|
333
|
+
|
|
334
|
+
const common: OidcReact.Common = {
|
|
335
|
+
params: oidc.params,
|
|
336
|
+
useAutoLogoutWarningCountdown
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
if (!oidc.isUserLoggedIn) {
|
|
340
|
+
return id<OidcReact.NotLoggedIn>({
|
|
341
|
+
...common,
|
|
342
|
+
isUserLoggedIn: false,
|
|
343
|
+
login: ({ doesCurrentHrefRequiresAuth = false, ...rest } = {}) =>
|
|
344
|
+
oidc.login({ doesCurrentHrefRequiresAuth, ...rest }),
|
|
345
|
+
initializationError: oidc.initializationError
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const oidcReact: OidcReact.LoggedIn<DecodedIdToken> = {
|
|
350
|
+
...common,
|
|
351
|
+
isUserLoggedIn: true,
|
|
352
|
+
decodedIdToken: oidc.getDecodedIdToken(),
|
|
353
|
+
logout: oidc.logout,
|
|
354
|
+
renewTokens: oidc.renewTokens,
|
|
355
|
+
goToAuthServer: oidc.goToAuthServer,
|
|
356
|
+
isNewBrowserSession: oidc.isNewBrowserSession,
|
|
357
|
+
backFromAuthServer: oidc.backFromAuthServer
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
return oidcReact;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function withLoginEnforced<Props extends Record<string, unknown>>(
|
|
364
|
+
Component: ComponentType<Props>,
|
|
365
|
+
params?: {
|
|
366
|
+
onRedirecting?: () => JSX.Element | null;
|
|
367
|
+
}
|
|
368
|
+
): FC<Props> {
|
|
369
|
+
const { onRedirecting } = params ?? {};
|
|
370
|
+
|
|
371
|
+
function ComponentWithLoginEnforced(props: Props) {
|
|
372
|
+
const contextValue = useContext(oidcContext);
|
|
373
|
+
|
|
374
|
+
assert(contextValue !== undefined, "094283");
|
|
375
|
+
|
|
376
|
+
const { oidc, fallback } = contextValue;
|
|
377
|
+
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
if (oidc.isUserLoggedIn) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
oidc.login({ doesCurrentHrefRequiresAuth: true });
|
|
384
|
+
}, []);
|
|
385
|
+
|
|
386
|
+
if (!oidc.isUserLoggedIn) {
|
|
387
|
+
return onRedirecting === undefined ? fallback : onRedirecting();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return <Component {...props} />;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
ComponentWithLoginEnforced.displayName = `${
|
|
394
|
+
Component.displayName ?? Component.name ?? "Component"
|
|
395
|
+
}WithLoginEnforced`;
|
|
396
|
+
|
|
397
|
+
return ComponentWithLoginEnforced;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function enforceLogin(loaderParams: {
|
|
401
|
+
request?: { url?: string };
|
|
402
|
+
cause?: "preload" | string;
|
|
403
|
+
location?: { href?: string };
|
|
404
|
+
}): Promise<void | never> {
|
|
405
|
+
const { cause } = loaderParams;
|
|
406
|
+
|
|
407
|
+
const redirectUrl = (() => {
|
|
408
|
+
if (loaderParams.request?.url !== undefined) {
|
|
409
|
+
return toFullyQualifiedUrl({
|
|
410
|
+
urlish: loaderParams.request.url,
|
|
411
|
+
doAssertNoQueryParams: false
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (loaderParams.location?.href !== undefined) {
|
|
416
|
+
return toFullyQualifiedUrl({
|
|
417
|
+
urlish: loaderParams.location.href,
|
|
418
|
+
doAssertNoQueryParams: false
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return location.href;
|
|
423
|
+
})();
|
|
424
|
+
|
|
425
|
+
const oidc = await getOidc();
|
|
426
|
+
|
|
427
|
+
if (!oidc.isUserLoggedIn) {
|
|
428
|
+
if (cause === "preload") {
|
|
429
|
+
throw new Error(
|
|
430
|
+
"oidc-spa: User is not yet logged in. This is an expected error, nothing to be addressed."
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
const doesCurrentHrefRequiresAuth =
|
|
434
|
+
location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
435
|
+
|
|
436
|
+
await oidc.login({
|
|
437
|
+
redirectUrl,
|
|
438
|
+
doesCurrentHrefRequiresAuth
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function getOidc(): Promise<Oidc<DecodedIdToken>> {
|
|
444
|
+
dReadyToCreate.resolve();
|
|
445
|
+
|
|
446
|
+
const oidcOrInitializationError = await prOidcOrInitializationError;
|
|
447
|
+
|
|
448
|
+
if (oidcOrInitializationError instanceof OidcInitializationError) {
|
|
449
|
+
const error = oidcOrInitializationError;
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const oidc = oidcOrInitializationError;
|
|
454
|
+
|
|
455
|
+
return oidc;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const oidcReact: OidcReactApi<DecodedIdToken, false> = {
|
|
459
|
+
OidcProvider,
|
|
460
|
+
useOidc: useOidc as any,
|
|
461
|
+
getOidc,
|
|
462
|
+
withLoginEnforced,
|
|
463
|
+
enforceLogin
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// @ts-expect-error: We know what we are doing
|
|
467
|
+
return oidcReact;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** @see: https://docs.oidc-spa.dev/v/v7/usage#react-api */
|
|
471
|
+
export function createReactOidc<
|
|
472
|
+
DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_base,
|
|
473
|
+
AutoLogin extends boolean = false
|
|
474
|
+
>(params: ValueOrAsyncGetter<ParamsOfCreateOidc<DecodedIdToken, AutoLogin>>) {
|
|
475
|
+
return createOidcReactApi_dependencyInjection(params, createOidc);
|
|
476
|
+
}
|