@enterprisestandard/react 0.0.3-beta.20251106.1 → 0.0.3-beta.20251110.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/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");
@@ -231,6 +278,31 @@ function sso(config) {
231
278
  return data;
232
279
  });
233
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
+ }
234
306
  async function fetchJwks() {
235
307
  const url = configWithDefaults.jwks_uri || `${configWithDefaults.authority}/protocol/openid-connect/certs`;
236
308
  const cached = jwksCache.get(url);
@@ -392,13 +464,20 @@ function sso(config) {
392
464
  return JSON.parse(str);
393
465
  }
394
466
  async function handler(request, handlerConfig) {
395
- let { loginUrl, userUrl, errorUrl, landingUrl, tokenUrl, refreshUrl, jwksUrl } = handlerConfig ?? {};
396
- if (!loginUrl)
397
- loginUrl = "*";
467
+ const { loginUrl, userUrl, errorUrl, landingUrl, tokenUrl, refreshUrl, logoutUrl, jwksUrl } = handlerConfig ?? {};
468
+ if (!loginUrl) {
469
+ console.error("loginUrl is required");
470
+ }
398
471
  const path = new URL(request.url).pathname;
399
472
  if (new URL(config.redirect_uri).pathname === path) {
400
473
  return callbackHandler(request);
401
474
  }
475
+ if (loginUrl === path) {
476
+ return initiateLogin({
477
+ landingUrl: landingUrl || "/",
478
+ errorUrl
479
+ });
480
+ }
402
481
  if (userUrl === path) {
403
482
  const { tokens, refreshHeaders } = await getTokenFromCookies(request);
404
483
  if (!tokens) {
@@ -434,18 +513,15 @@ function sso(config) {
434
513
  headers: refreshHeaders
435
514
  });
436
515
  }
516
+ if (logoutUrl === path) {
517
+ return logout(request, { landingUrl: landingUrl || "/" });
518
+ }
437
519
  if (jwksUrl === path) {
438
520
  const jwks = await fetchJwks();
439
521
  return new Response(JSON.stringify(jwks), {
440
522
  headers: [["Content-Type", "application/json"]]
441
523
  });
442
524
  }
443
- if (loginUrl === "*" || loginUrl === path) {
444
- return initiateLogin({
445
- landingUrl: landingUrl || "/",
446
- errorUrl
447
- });
448
- }
449
525
  return new Response("Not Found", { status: 404 });
450
526
  }
451
527
  return {
@@ -453,6 +529,7 @@ function sso(config) {
453
529
  getRequiredUser,
454
530
  getJwt,
455
531
  initiateLogin,
532
+ logout,
456
533
  callbackHandler,
457
534
  handler
458
535
  };
@@ -781,9 +858,14 @@ function SSOProvider({
781
858
  }
782
859
  }
783
860
  };
861
+ const handleLogout = () => {
862
+ setUserState(null);
863
+ };
784
864
  window.addEventListener("storage", handleStorageChange);
865
+ window.addEventListener("es-sso-logout", handleLogout);
785
866
  return () => {
786
867
  window.removeEventListener("storage", handleStorageChange);
868
+ window.removeEventListener("es-sso-logout", handleLogout);
787
869
  };
788
870
  }, [disableListener, storage, actualStorageKey, isValidUser]);
789
871
  const contextValue = {
@@ -882,6 +964,41 @@ function useToken() {
882
964
  refresh
883
965
  };
884
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
+ }
885
1002
 
886
1003
  // src/index.ts
887
1004
  async function enterpriseStandard(appId, appKey, initConfig) {
@@ -927,6 +1044,7 @@ export {
927
1044
  useUser,
928
1045
  useToken,
929
1046
  oidcCallbackSchema,
1047
+ logout,
930
1048
  initiateLogin,
931
1049
  handler,
932
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;
@@ -30,12 +30,15 @@ export type SSOHandlerConfig = {
30
30
  tokenUrl?: string;
31
31
  refreshUrl?: string;
32
32
  jwksUrl?: string;
33
+ logoutUrl?: string;
34
+ logoutCallbackUrl?: string;
33
35
  } & ESConfig;
34
36
  export type SSO = {
35
37
  getUser: (request: Request) => Promise<EnterpriseUser | undefined>;
36
38
  getRequiredUser: (request: Request) => Promise<EnterpriseUser>;
37
39
  getJwt: (request: Request) => Promise<string | undefined>;
38
40
  initiateLogin: (config: LoginConfig) => Promise<Response>;
41
+ logout: (request: Request, config?: LoginConfig) => Promise<Response>;
39
42
  callbackHandler: (request: Request) => Promise<Response>;
40
43
  handler: (request: Request, handlerConfig?: SSOHandlerConfig) => Promise<Response>;
41
44
  };
@@ -27,4 +27,8 @@ interface UseTokenReturn {
27
27
  refresh: () => Promise<void>;
28
28
  }
29
29
  export declare function useToken(): UseTokenReturn;
30
+ export declare function logout(logoutUrl: string): Promise<{
31
+ success: boolean;
32
+ error?: string;
33
+ }>;
30
34
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enterprisestandard/react",
3
- "version": "0.0.3-beta.20251106.1",
3
+ "version": "0.0.3-beta.20251110.2",
4
4
  "description": "Enterprise Standard React Components",
5
5
  "private": false,
6
6
  "main": "dist/index.js",