UNPKG

@kinde-oss/kinde-auth-react

Version:

Kinde React SDK for authentication

626 lines (625 loc) 16.3 kB
import { n as e, t } from "./useKindeAuth-BFlFfLEC.js"; import { $ as n, A as r, C as i, D as a, F as o, H as ee, K as s, Q as te, Z as c, _ as l, _t as u, a as ne, ct as re, d, et as ie, g as ae, gt as f, i as oe, k as se, m as ce, mt as le, n as ue, ot as de, p, rt as m, st as h, tt as g, v as fe, w as pe, yt as _ } from "./js-utils-BNG8ijcF.js"; import me, { useCallback as v, useEffect as y, useMemo as he, useRef as b, useState as x } from "react"; import { Fragment as ge, jsx as S } from "react/jsx-runtime"; //#region src/state/store.ts var C = /* @__PURE__ */ function(e) { return e.performingLogout = "performing_logout", e; }(C || {}), _e = new re(), w = new s(); ce(_e), l(w); //#endregion //#region src/utils/getRedirectUrl.ts var T = (e) => e || window.location.origin, ve = { name: "@kinde-oss/kinde-auth-react", version: "5.13.0", description: "Kinde React SDK for authentication", module: "./dist/index.mjs", main: "./dist/index.cjs", types: "./dist/index.d.ts", type: "module", exports: { ".": { types: "./dist/src/index.d.ts", import: "./dist/index.mjs", require: "./dist/index.cjs" }, "./components": { types: "./dist/src/components/index.d.ts", import: "./dist/components.mjs", require: "./dist/components.cjs" }, "./utils": { types: "./dist/src/utils/index.d.ts", import: "./dist/utils.mjs", require: "./dist/utils.cjs" }, "./react-router": { types: "./dist/src/components/react-router-dom/index.d.ts", import: "./dist/react-router.mjs", require: "./dist/react-router.cjs" } }, scripts: { build: "tsc && vite build", test: "vitest", "test:coverage": "vitest --coverage", release: "release-it", lint: "prettier --check .", "lint:fix": "prettier --write .", "dev:prepare": "rm -rf playground && git clone https://github.com/kinde-starter-kits/react-starter-kit playground && cd playground && printf \"overrides:\\n '@kinde-oss/kinde-auth-react': link:..\\n\" > pnpm-workspace.yaml && pnpm install && mv .env_sample .env && rm -rf .git", dev: "cd playground && npm start" }, author: { name: "Kinde", email: "engineering@kinde.com", url: "https://kinde.com" }, repository: { type: "git", url: "https://github.com/kinde-oss/kinde-auth-react" }, bugs: "https://github.com/kinde-oss/kinde-auth-react", homepage: "https://kinde.com", license: "MIT", devDependencies: { "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^10.0.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@types/node": "^24.0.0", "@types/react": "19.2.17", "@typescript-eslint/eslint-plugin": "8.65.0", "@typescript-eslint/parser": "8.65.0", "@typescript/typescript6": "6.0.2", "@vitejs/plugin-react": "^6.0.0", "@vitest/coverage-v8": "^4.0.0", eslint: "10.7.0", "eslint-config-prettier": "^10.0.2", "eslint-plugin-react": "^7.37.4", globals: "^17.0.0", jsdom: "^29.0.0", prettier: "^3.5.2", react: "^19.2.4", "react-dom": "^19.2.4", "release-it": "^20.0.0", typescript: "7.0.2", vite: "^8.0.0", "vite-plugin-dts": "^5.0.0", vitest: "^4.0.0" }, keywords: [ "Kinde", "login", "Authorization Code Grant Flow", "PKCE", "Single Page Application authentication", "React authentication" ], peerDependencies: { react: "^17 || ^18 || >=19.2.1", "react-dom": "^17 || ^18 || >=19.2.1" }, files: [ "dist", "src", "LICENSE.md" ], private: !1, dependencies: { "@kinde/js-utils": "0.32.0" }, packageManager: "pnpm@11.15.1" }, ye = /* @__PURE__ */ function(e) { return e.preWarning = "preWarning", e.timeout = "timeout", e; }({}); //#endregion //#region src/state/KindeProvider.tsx g.keyPrefix = ""; var be = { onSuccess: () => { window.history.replaceState({}, document.title, window.location.pathname); } }, E = () => { try { let e = window.opener; return !e || e.closed ? !1 : e.location.origin === window.location.origin; } catch { return !1; } }, xe = (e, { skipInitial: t = !1 } = {}) => { let n = b(!0); y(() => { let r = () => { if (t && n.current) { n.current = !1; return; } e(window.location); }, i = () => r(); window.addEventListener("popstate", i), window.addEventListener("hashchange", i); let a = history.pushState, o = history.replaceState; return history.pushState === a && (history.pushState = function(...e) { a.apply(this, e), r(); }), history.replaceState === o && (history.replaceState = function(...e) { o.apply(this, e), r(); }), () => { window.removeEventListener("popstate", i), window.removeEventListener("hashchange", i), history.pushState = a, history.replaceState = o; }; }, [e, t]); }, D = ({ audience: t, scope: s, clientId: l, children: re, domain: D, useInsecureForRefreshToken: Se = !1, redirectUri: O, callbacks: k = {}, logoutUri: A, forceChildrenRender: j = !1, popupOptions: M = {}, store: N = _e, activityTimeout: P, refreshOnFocus: F = !1 }) => { let [I] = x(() => { if (typeof window > "u") return { invitationCode: null, redirectPending: !1 }; let e = new URLSearchParams(window.location.search); return { invitationCode: e.get("invitation_code"), redirectPending: e.has("invitation_code") }; }), L = b(I.invitationCode), [R, z] = x(() => I.redirectPending), B = he(() => ({ ...be, ...k }), [k]), [V, Ce] = x(!1), [H, U] = x({ user: void 0, isAuthenticated: !1, isLoading: !0 }), [we, Te] = x(j), W = b(null), G = v((e) => { j && U((t) => ({ ...t, isLoading: e })); }, [j]); xe(v((e) => { V && P && H.isAuthenticated && m(); }, [ V, P, H.isAuthenticated ]), P ? {} : { skipInitial: !0 }), y(() => { ce(N); let e = () => { if (!(!P || V)) { g.activityTimeoutMinutes = P.timeoutMinutes, g.activityTimeoutPreWarningMinutes = P.preWarningMinutes, g.onActivityTimeout = async (e, t) => { try { if (e === ye.timeout) { let e = t?.accessToken, n = t?.refreshToken, r = async (e, t) => { if (!e) return; let n = await fetch(`${D}/oauth2/revoke`, { method: "POST", body: `token=${encodeURIComponent(e)}&client_id=${encodeURIComponent(l)}&token_type_hint=${t}`, headers: { "Content-Type": "application/x-www-form-urlencoded" } }); n.ok || console.warn(`Failed to revoke ${t}:`, n.status); }; await Promise.allSettled([r(e, "access_token"), r(n, "refresh_token")]); } } catch (e) { console.error("Failed to logout:", e); } finally { P.onTimeout?.(e); } }; try { m(); } catch (e) { console.error("Failed to update activity timestamp:", e); return; } Ce(!0); } }, t = () => { V && (g.activityTimeoutMinutes = void 0, g.activityTimeoutPreWarningMinutes = void 0, g.onActivityTimeout = void 0, Ce(!1)); }, n = N.subscribe(async () => { try { let [n, i] = await Promise.all([r(), p()]); n && i ? (e(), U((e) => ({ ...e, user: i, isAuthenticated: !0 }))) : (t(), U((e) => ({ ...e, user: void 0, isAuthenticated: !1 }))); } catch (e) { console.error("Store subscription update failed:", e), t(), U((e) => ({ ...e, user: void 0, isAuthenticated: !1 })); } }); return () => { n(), t(); }; }, [ N, P, V ]), _.framework = "react", _.frameworkVersion = me.version, _.sdkVersion = ve.version, g.useInsecureForRefreshToken = Se; let K = b(!1), q = b(!1), J = v(async (e = {}) => { G(!0); let n = e.state || {}; e.state = void 0; let r = { audience: t, clientId: l, ...e, supportsReauth: !0, scope: s?.split(" "), state: h(JSON.stringify({ kinde: { event: "login" }, ...n })), redirectURL: T(e.redirectURL || O) }, i = await c(D, te.login, r); try { u({ url: i.url.toString(), popupOptions: M, handleResult: Z }); } catch (e) { if (G(!1), !W.current) { console.error("Login error (context unavailable):", e); return; } B.onError?.({ error: "ERR_POPUP", errorDescription: e.message }, {}, W.current); } }, [ t, l, O, M, B, D, s, G ]); y(() => { R && L.current && !q.current && (q.current = !0, J({ prompt: f.create, invitationCode: L.current }).catch((e) => { console.error("Error processing invitation code:", e), W.current ? B.onError?.({ error: "ERR_INVITATION_REDIRECT", errorDescription: e instanceof Error ? e.message : String(e) }, {}, W.current) : console.error("Invitation redirect error (context unavailable):", e), q.current = !1, z(!1); })); }, [ J, R, B ]); let Ee = v(async (e = {}) => { G(!0); let n = e.state || {}; e.state = void 0; let r = { ...e, state: h(JSON.stringify({ kinde: { event: "register" }, ...n })), supportsReauth: !0, audience: t, clientId: l, redirectURL: T(e?.redirectURL || O), prompt: f.create }; try { let e = await c(D, te.register, r); try { u({ url: e.url.toString(), popupOptions: M, handleResult: Z }); } catch (e) { if (G(!1), !W.current) { console.error("Register error (context unavailable):", e); return; } B.onError?.({ error: "ERR_POPUP", errorDescription: e.message }, {}, W.current); } } catch (e) { if (G(!1), console.error("Register error:", e), !W.current) return; B.onError?.({ error: "ERR_REGISTER", errorDescription: String(e) }, {}, W.current); } }, [ O, M, B, t, l, D, G ]), De = v(async (e) => { G(!0); try { let t = new URLSearchParams(); e ? e && typeof e == "string" ? t.append("redirect", e) : typeof e == "object" && ((e.redirectUrl || A) && t.append("redirect", e.redirectUrl || A || ""), e.allSessions && t.append("all_sessions", String(e.allSessions))) : t.append("redirect", A || ""), await Promise.all([ N.removeSessionItem(a.idToken), N.removeSessionItem(a.accessToken), N.removeSessionItem(a.refreshToken), w.removeSessionItem(a.refreshToken) ]), U((e) => ({ ...e, user: void 0, isAuthenticated: !1 })), await w.setSessionItem(C.performingLogout, "true"); try { await u({ url: `${D}/logout?${t.toString()}`, popupOptions: M, handleResult: async () => { G(!1); } }); } catch (e) { if (G(!1), !W.current) { console.error("Logout error (context unavailable):", e); return; } B.onError?.({ error: "ERR_POPUP", errorDescription: e.message }, {}, W.current); } } catch (e) { if (G(!1), console.error("Logout error:", e), !W.current) return; B.onError?.({ error: "ERR_LOGOUT", errorDescription: String(e) }, {}, W.current); } }, [ N, M, B, A, D, G ]), Y = he(() => ({ login: J, logout: De, register: Ee, getIdToken: async () => await i()?.getSessionItem(a.idToken), getAccessToken: async () => await i()?.getSessionItem(a.accessToken), getToken: async () => await i()?.getSessionItem(a.accessToken), getClaim: async (e, t) => ae(e, t), getClaims: async (...e) => fe(...e), getOrganization: async () => await d(), getCurrentOrganization: async () => await d(), getFlag: async (e) => await ie(e), getUserProfile: p, getPermission: async (e) => await pe(e), getPermissions: async () => oe(), getUserOrganizations: async () => await ne(), getRoles: async () => await se(), generatePortalUrl: async (e) => await ue({ domain: D, returnUrl: e.returnUrl || window.location.href, subNav: e.subNav }), switchOrg: async (e) => { let t = await n({ domain: D, clientId: l, orgCode: e, redirectURL: O }); window.location.href = t.url.toString(); }, refreshToken: async (...e) => await o(...e), ...H }), [ H, J, De, Ee, D, l, O ]); W.current = Y; let X = v((e) => { B.onEvent && B.onEvent("tokenRefreshed", e, Y), !e.success && B.onError && B.onError({ error: "ERR_REFRESH_TOKEN", errorDescription: e.error ?? "Token refresh failed" }, {}, Y); }, [B, Y]), Z = v(async (e) => { try { let t = e.get("state") || "", n; try { n = le(t); } catch (e) { B.onError?.({ error: "ERR_STATE_DECODE", errorDescription: `Invalid state parameter: ${String(e)}` }, {}, Y), U((e) => ({ ...e, isLoading: !1 })); return; } let r, i; try { r = JSON.parse(n), i = Object.assign(r.kinde || { event: f.login }); } catch (e) { console.error("Error parsing state:", e), B.onError?.({ error: "ERR_STATE_PARSE", errorDescription: String(e) }, {}, Y), r = {}, i = { event: "login" }; } try { let t = await de({ urlParams: e, domain: D, clientId: l, redirectURL: T(O), autoRefresh: !0, onRefresh: X }); if (t.success) { let e = await p(); e && (U((t) => ({ ...t, user: e, isAuthenticated: !0 })), B.onSuccess?.(e, { ...r, kinde: void 0 }, Y), B.onEvent && B.onEvent(i.event, { ...r, kinde: void 0 }, Y)); } else B.onError?.({ error: "ERR_CODE_EXCHANGE", errorDescription: t.error }, r, Y); } catch (e) { B.onError?.({ error: "ERR_POPUP_AUTH", errorDescription: String(e) }, r, Y); } finally { j ? G(!1) : U((e) => ({ ...e, isLoading: !1 })); } } finally { z(!1); } }, [ D, l, O, X, B, Y, G, j, z ]), Q = v(() => { document.visibilityState === "visible" && H.isAuthenticated && F && o({ domain: D, clientId: l, onRefresh: X }).then((e) => { e.success || console.error("Error refreshing token:", e.error); }).catch((e) => { console.error("Error refreshing token:", e), B.onError?.({ error: "ERR_REFRESH_TOKEN", errorDescription: e instanceof Error ? e.message : String(e) }, {}, Y); }); }, [ H.isAuthenticated, D, l, X, F, B, Y ]); y(() => { if (document.removeEventListener("visibilitychange", Q), F) return document.addEventListener("visibilitychange", Q), () => { document.removeEventListener("visibilitychange", Q); }; }, [Q, F]); let $ = v(async () => { if (!K.current && (j && Te(!0), !(!D || !l || !O))) try { if (R) return; let e = new URLSearchParams(window.location.search); try { K.current = !0; let e = await ee({ domain: D, clientId: l }); e && !e.success && B.onError?.({ error: "ERR_CHECK_AUTH", errorDescription: e.error ?? "Authentication check failed" }, {}, Y); } catch (e) { console.warn("checkAuth failed:", e), B.onError?.({ error: "ERR_CHECK_AUTH", errorDescription: e instanceof Error ? e.message : String(e) }, {}, Y); } if (e.has("error")) { if (e.get("error")?.toLowerCase() === "login_link_expired") { let t = e.get("reauth_state"); t && J({ reauthState: t }); return; } U((e) => ({ ...e, isLoading: !1 })); return; } await w.getSessionItem(C.performingLogout) === "true" && (await w.removeSessionItem(C.performingLogout), E() && window.close()); let t = new URL(window.location.href), n = new URL(O); if (t.origin === n.origin && t.pathname === n.pathname && e.has("code")) { if (E()) { let e = new URLSearchParams(window.location.search); window.opener.postMessage({ type: "KINDE_AUTH_RESULT", result: Object.fromEntries(e.entries()) }, window.location.origin), window.close(); return; } await Z(new URLSearchParams(window.location.search)); return; } try { let e = await p(); e && U((t) => ({ ...t, user: e, isAuthenticated: !0 })); } catch (e) { console.warn("Error getting user profile", e); } finally { U((e) => ({ ...e, isLoading: !1 })); } } finally { E() && window.close(); } }, [ l, D, O, B, Y, X, J, Z, R, j ]); return y(() => { let e = { current: !0 }; return e.current && $(), () => { e.current = !1; }; }, [$]), R && !j ? /* @__PURE__ */ S(ge, {}) : (j ? we : K.current) ? /* @__PURE__ */ S(e.Provider, { value: Y, children: re }) : /* @__PURE__ */ S(ge, {}); }; //#endregion export { e as KindeContext, D as KindeProvider, ye as TimeoutActivityType, t as useKindeAuth };