@enterprisestandard/react 0.0.3-beta.20251029.3 → 0.0.3-beta.20251110.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +132 -7
- package/dist/sso.d.ts +5 -1
- package/dist/ui/sso-provider.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ function getES(es) {
|
|
|
31
31
|
|
|
32
32
|
// src/sso.ts
|
|
33
33
|
var jwksCache = new Map;
|
|
34
|
+
var _logoutTokenJtis = new Set;
|
|
34
35
|
function sso(config) {
|
|
35
36
|
const configWithDefaults = {
|
|
36
37
|
...config,
|
|
@@ -93,6 +94,52 @@ function sso(config) {
|
|
|
93
94
|
}
|
|
94
95
|
});
|
|
95
96
|
}
|
|
97
|
+
async function logout(request, _config) {
|
|
98
|
+
try {
|
|
99
|
+
const refreshToken2 = getCookie("refresh", request);
|
|
100
|
+
if (refreshToken2) {
|
|
101
|
+
await revokeToken(refreshToken2);
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn("Failed to revoke token:", error);
|
|
105
|
+
}
|
|
106
|
+
const clearHeaders = [
|
|
107
|
+
["Set-Cookie", clearCookie("access")],
|
|
108
|
+
["Set-Cookie", clearCookie("id")],
|
|
109
|
+
["Set-Cookie", clearCookie("refresh")],
|
|
110
|
+
["Set-Cookie", clearCookie("control")],
|
|
111
|
+
["Set-Cookie", clearCookie("state")]
|
|
112
|
+
];
|
|
113
|
+
const url = new URL(request.url);
|
|
114
|
+
const redirectTo = url.searchParams.get("redirect");
|
|
115
|
+
if (redirectTo) {
|
|
116
|
+
return new Response("Logged out", {
|
|
117
|
+
status: 302,
|
|
118
|
+
headers: [["Location", redirectTo], ...clearHeaders]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const accept = request.headers.get("accept");
|
|
122
|
+
const isAjax = accept?.includes("application/json") || accept?.includes("text/javascript");
|
|
123
|
+
if (isAjax) {
|
|
124
|
+
return new Response(JSON.stringify({ success: true, message: "Logged out" }), {
|
|
125
|
+
status: 200,
|
|
126
|
+
headers: [["Content-Type", "application/json"], ...clearHeaders]
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
return new Response(`
|
|
130
|
+
<!DOCTYPE html><html lang="en"><body>
|
|
131
|
+
<h1>Logout Complete</h1>
|
|
132
|
+
<div style="display: none">
|
|
133
|
+
It is not recommended to show the default logout page. Include '?redirect=/someHomePage' or logout asynchronously.
|
|
134
|
+
Check the <a href="https://EnterpriseStandard.com/sso#logout">Enterprise Standard Packages</a> for more information.
|
|
135
|
+
</div>
|
|
136
|
+
</body></html>
|
|
137
|
+
`, {
|
|
138
|
+
status: 200,
|
|
139
|
+
headers: [["Content-Type", "text/html"], ...clearHeaders]
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
96
143
|
async function callbackHandler(request) {
|
|
97
144
|
if (!configWithDefaults) {
|
|
98
145
|
console.error("SSO Manager not initialized");
|
|
@@ -148,6 +195,7 @@ function sso(config) {
|
|
|
148
195
|
const expiresIn = Number(token.refresh_expires_in ?? token.expires_in ?? 3600);
|
|
149
196
|
const expires = token.expires ? new Date(token.expires) : new Date(Date.now() + expiresIn * 1000);
|
|
150
197
|
return {
|
|
198
|
+
id: idToken.sub,
|
|
151
199
|
userName: idToken.preferred_username || "",
|
|
152
200
|
name: idToken.name || "",
|
|
153
201
|
email: idToken.email || "",
|
|
@@ -230,6 +278,31 @@ function sso(config) {
|
|
|
230
278
|
return data;
|
|
231
279
|
});
|
|
232
280
|
}
|
|
281
|
+
async function revokeToken(token) {
|
|
282
|
+
try {
|
|
283
|
+
if (!configWithDefaults)
|
|
284
|
+
throw new Error("SSO Manager not initialized");
|
|
285
|
+
const revokeUrl = `${configWithDefaults.authority}/protocol/openid-connect/revoke`;
|
|
286
|
+
const body = new URLSearchParams;
|
|
287
|
+
body.append("token", token);
|
|
288
|
+
body.append("token_type_hint", "refresh_token");
|
|
289
|
+
body.append("client_id", configWithDefaults.client_id);
|
|
290
|
+
const response = await fetch(revokeUrl, {
|
|
291
|
+
method: "POST",
|
|
292
|
+
headers: {
|
|
293
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
294
|
+
},
|
|
295
|
+
body: body.toString()
|
|
296
|
+
});
|
|
297
|
+
if (!response.ok) {
|
|
298
|
+
console.warn("Token revocation failed:", response.status, response.statusText);
|
|
299
|
+
} else {
|
|
300
|
+
console.log("Token revoked successfully");
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.warn("Error revoking token:", error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
233
306
|
async function fetchJwks() {
|
|
234
307
|
const url = configWithDefaults.jwks_uri || `${configWithDefaults.authority}/protocol/openid-connect/certs`;
|
|
235
308
|
const cached = jwksCache.get(url);
|
|
@@ -391,13 +464,20 @@ function sso(config) {
|
|
|
391
464
|
return JSON.parse(str);
|
|
392
465
|
}
|
|
393
466
|
async function handler(request, handlerConfig) {
|
|
394
|
-
|
|
395
|
-
if (!loginUrl)
|
|
396
|
-
loginUrl
|
|
467
|
+
const { loginUrl, userUrl, errorUrl, landingUrl, tokenUrl, refreshUrl, logoutUrl, jwksUrl } = handlerConfig ?? {};
|
|
468
|
+
if (!loginUrl) {
|
|
469
|
+
console.error("loginUrl is required");
|
|
470
|
+
}
|
|
397
471
|
const path = new URL(request.url).pathname;
|
|
398
472
|
if (new URL(config.redirect_uri).pathname === path) {
|
|
399
473
|
return callbackHandler(request);
|
|
400
474
|
}
|
|
475
|
+
if (loginUrl === path) {
|
|
476
|
+
return initiateLogin({
|
|
477
|
+
landingUrl: landingUrl || "/",
|
|
478
|
+
errorUrl
|
|
479
|
+
});
|
|
480
|
+
}
|
|
401
481
|
if (userUrl === path) {
|
|
402
482
|
const { tokens, refreshHeaders } = await getTokenFromCookies(request);
|
|
403
483
|
if (!tokens) {
|
|
@@ -433,10 +513,13 @@ function sso(config) {
|
|
|
433
513
|
headers: refreshHeaders
|
|
434
514
|
});
|
|
435
515
|
}
|
|
436
|
-
if (
|
|
437
|
-
return
|
|
438
|
-
|
|
439
|
-
|
|
516
|
+
if (logoutUrl === path) {
|
|
517
|
+
return logout(request, { landingUrl: landingUrl || "/" });
|
|
518
|
+
}
|
|
519
|
+
if (jwksUrl === path) {
|
|
520
|
+
const jwks = await fetchJwks();
|
|
521
|
+
return new Response(JSON.stringify(jwks), {
|
|
522
|
+
headers: [["Content-Type", "application/json"]]
|
|
440
523
|
});
|
|
441
524
|
}
|
|
442
525
|
return new Response("Not Found", { status: 404 });
|
|
@@ -446,6 +529,7 @@ function sso(config) {
|
|
|
446
529
|
getRequiredUser,
|
|
447
530
|
getJwt,
|
|
448
531
|
initiateLogin,
|
|
532
|
+
logout,
|
|
449
533
|
callbackHandler,
|
|
450
534
|
handler
|
|
451
535
|
};
|
|
@@ -774,9 +858,14 @@ function SSOProvider({
|
|
|
774
858
|
}
|
|
775
859
|
}
|
|
776
860
|
};
|
|
861
|
+
const handleLogout = () => {
|
|
862
|
+
setUserState(null);
|
|
863
|
+
};
|
|
777
864
|
window.addEventListener("storage", handleStorageChange);
|
|
865
|
+
window.addEventListener("es-sso-logout", handleLogout);
|
|
778
866
|
return () => {
|
|
779
867
|
window.removeEventListener("storage", handleStorageChange);
|
|
868
|
+
window.removeEventListener("es-sso-logout", handleLogout);
|
|
780
869
|
};
|
|
781
870
|
}, [disableListener, storage, actualStorageKey, isValidUser]);
|
|
782
871
|
const contextValue = {
|
|
@@ -875,6 +964,41 @@ function useToken() {
|
|
|
875
964
|
refresh
|
|
876
965
|
};
|
|
877
966
|
}
|
|
967
|
+
async function logout(logoutUrl) {
|
|
968
|
+
try {
|
|
969
|
+
const response = await fetch(logoutUrl, {
|
|
970
|
+
headers: { Accept: "application/json" }
|
|
971
|
+
});
|
|
972
|
+
if (!response.ok) {
|
|
973
|
+
return { success: false, error: `HTTP ${response.status}` };
|
|
974
|
+
}
|
|
975
|
+
const data = await response.json();
|
|
976
|
+
if (!data.success) {
|
|
977
|
+
return { success: false, error: data.message || "Logout failed" };
|
|
978
|
+
}
|
|
979
|
+
if (typeof window !== "undefined") {
|
|
980
|
+
for (let i = localStorage.length - 1;i >= 0; i--) {
|
|
981
|
+
const key = localStorage.key(i);
|
|
982
|
+
if (key?.startsWith("es-sso-user")) {
|
|
983
|
+
localStorage.removeItem(key);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
for (let i = sessionStorage.length - 1;i >= 0; i--) {
|
|
987
|
+
const key = sessionStorage.key(i);
|
|
988
|
+
if (key?.startsWith("es-sso-user")) {
|
|
989
|
+
sessionStorage.removeItem(key);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
window.dispatchEvent(new CustomEvent("es-sso-logout"));
|
|
993
|
+
}
|
|
994
|
+
return { success: true };
|
|
995
|
+
} catch (error) {
|
|
996
|
+
return {
|
|
997
|
+
success: false,
|
|
998
|
+
error: error instanceof Error ? error.message : "Network error"
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
878
1002
|
|
|
879
1003
|
// src/index.ts
|
|
880
1004
|
async function enterpriseStandard(appId, appKey, initConfig) {
|
|
@@ -920,6 +1044,7 @@ export {
|
|
|
920
1044
|
useUser,
|
|
921
1045
|
useToken,
|
|
922
1046
|
oidcCallbackSchema,
|
|
1047
|
+
logout,
|
|
923
1048
|
initiateLogin,
|
|
924
1049
|
handler,
|
|
925
1050
|
getUser,
|
package/dist/sso.d.ts
CHANGED
|
@@ -7,13 +7,13 @@ export type SSOConfig = {
|
|
|
7
7
|
redirect_uri: string;
|
|
8
8
|
response_type: string;
|
|
9
9
|
scope: string;
|
|
10
|
-
post_logout_redirect_uri?: string;
|
|
11
10
|
silent_redirect_uri?: string;
|
|
12
11
|
jwks_uri?: string;
|
|
13
12
|
cookies_prefix?: string;
|
|
14
13
|
cookies_path?: string;
|
|
15
14
|
cookies_secure?: boolean;
|
|
16
15
|
cookies_same_site?: 'Strict' | 'Lax';
|
|
16
|
+
end_session_endpoint?: string;
|
|
17
17
|
};
|
|
18
18
|
export type ESConfig = {
|
|
19
19
|
es?: EnterpriseStandard;
|
|
@@ -29,12 +29,16 @@ export type SSOHandlerConfig = {
|
|
|
29
29
|
landingUrl?: string;
|
|
30
30
|
tokenUrl?: string;
|
|
31
31
|
refreshUrl?: string;
|
|
32
|
+
jwksUrl?: string;
|
|
33
|
+
logoutUrl?: string;
|
|
34
|
+
logoutCallbackUrl?: string;
|
|
32
35
|
} & ESConfig;
|
|
33
36
|
export type SSO = {
|
|
34
37
|
getUser: (request: Request) => Promise<EnterpriseUser | undefined>;
|
|
35
38
|
getRequiredUser: (request: Request) => Promise<EnterpriseUser>;
|
|
36
39
|
getJwt: (request: Request) => Promise<string | undefined>;
|
|
37
40
|
initiateLogin: (config: LoginConfig) => Promise<Response>;
|
|
41
|
+
logout: (request: Request, config?: LoginConfig) => Promise<Response>;
|
|
38
42
|
callbackHandler: (request: Request) => Promise<Response>;
|
|
39
43
|
handler: (request: Request, handlerConfig?: SSOHandlerConfig) => Promise<Response>;
|
|
40
44
|
};
|