UNPKG

@kinde-oss/kinde-auth-react

Version:

Kinde React SDK for authentication

817 lines (816 loc) 22.7 kB
var q = /* @__PURE__ */ ((e) => (e.email = "email", e.profile = "profile", e.openid = "openid", e.offline_access = "offline", e))(q || {}), j = /* @__PURE__ */ ((e) => (e.none = "none", e.create = "create", e.login = "login", e))(j || {}), D = /* @__PURE__ */ ((e) => (e.organizationDetails = "organization_details", e.organizationMembers = "organization_members", e.organizationPlanDetails = "organization_plan_details", e.organizationPaymentDetails = "organization_payment_details", e.organizationPlanSelection = "organization_plan_selection", e.profile = "profile", e))(D || {}), J = /* @__PURE__ */ ((e) => (e.organizationDetails = "organization_details", e.organizationMembers = "organization_members", e.organizationPlanDetails = "organization_plan_details", e.organizationPaymentDetails = "organization_payment_details", e.organizationPlanSelection = "organization_plan_selection", e.profile = "profile", e))(J || {}), x = /* @__PURE__ */ ((e) => (e.logout = "logout", e.login = "login", e.register = "registration", e.token = "token", e.profile = "profile", e))(x || {}), p = /* @__PURE__ */ ((e) => (e[e.refreshToken = 0] = "refreshToken", e[e.cookie = 1] = "cookie", e))(p || {}); const A = (e) => { const r = (t) => btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); if (e instanceof ArrayBuffer) { const t = new Uint8Array(e), u = String.fromCharCode(...t); return r(u); } const n = new TextEncoder().encode(e), o = String.fromCharCode(...n); return r(o); }, P = (e = 28) => { if (crypto) { const r = new Uint8Array(e / 2); return crypto.getRandomValues(r), Array.from(r, K).join(""); } else return G(e); }; function K(e) { return e.toString(16).padStart(2, "0"); } function G(e = 28) { const r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let n = ""; const o = r.length; for (let t = 0; t < e; t++) n += r.charAt(Math.floor(Math.random() * o)); return n; } const ee = (e) => { e = e.split("?")[1]; const r = new URLSearchParams(e); return { accessToken: r.get("access_token"), idToken: r.get("id_token"), expiresIn: +(r.get("expires_in") || 0) }; }, R = (e) => e.replace(/\/$/, ""), H = (e, r = !1) => { const n = Array.isArray(e.audience) ? e.audience.join(" ") : e.audience || "", o = { login_hint: e.loginHint, is_create_org: e.isCreateOrg?.toString(), connection_id: e.connectionId, redirect_uri: e.redirectURL ? r ? e.redirectURL : R(e.redirectURL) : void 0, audience: n, scope: e.scope?.join(" ") || "email profile openid offline", prompt: e.prompt, lang: e.lang, org_code: e.orgCode, org_name: e.orgName, has_success_page: e.hasSuccessPage?.toString(), workflow_deployment_id: e.workflowDeploymentId, supports_reauth: e.supportsReauth?.toString(), plan_interest: e.planInterest }; return Object.keys(o).forEach( (t) => o[t] === void 0 && delete o[t] ), o; }, C = (e) => typeof e != "object" || e === null ? e : Array.isArray(e) ? e.map((r) => C(r)) : Object.fromEntries( Object.entries(e).map(([r, n]) => [ r.replace(/_([a-z])/g, (o, t) => t.toUpperCase()), C(n) ]) ), W = [ // UTM tags "utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term", // Google Ads smart campaign tracking "gclid", "click_id", "hsa_acc", "hsa_cam", "hsa_grp", "hsa_ad", "hsa_src", "hsa_tgt", "hsa_kw", "hsa_mt", "hsa_net", "hsa_ver", // Marketing category "match_type", "keyword", "device", "ad_group_id", "campaign_id", "creative", "network", "ad_position", "fbclid", "li_fat_id", "msclkid", "twclid", "ttclid" ], re = async (e, r = x.login, n, o) => { const t = `${e}/oauth2/auth`, u = T(); if (n.reauthState) try { const l = C( JSON.parse(atob(n.reauthState)) ); n = { ...n, ...l }, delete n.reauthState; } catch (l) { const h = l instanceof Error ? l.message : "Unknown error"; throw new Error(`Error handing reauth state: ${h}`); } if (!n.clientId) throw new Error("Error generating auth URL: Client ID missing"); const a = { client_id: n.clientId, response_type: n.responseType || "code", ...H(n, o?.disableUrlSanitization) }; n.state || (n.state = P(32)), u && u.setSessionItem(s.state, n.state), a.state = n.state, n.nonce || (n.nonce = P(16)), a.nonce = n.nonce, u && u.setSessionItem(s.nonce, n.nonce); let d = ""; if (n.codeChallenge) a.code_challenge = n.codeChallenge; else { const { codeVerifier: l, codeChallenge: h } = await B(); d = l, u && u.setSessionItem(s.codeVerifier, l), a.code_challenge = h; } a.code_challenge_method = "S256", n.codeChallengeMethod && (a.code_challenge_method = n.codeChallengeMethod), !n.prompt && r === x.register && (a.prompt = j.create), n.properties && Object.keys(n.properties).forEach((l) => { if (!W.includes(l)) { console.warn("Unsupported Property for url generation: ", l); return; } const h = n.properties?.[l]; h !== void 0 && (a[l] = h); }); const c = new URLSearchParams(a).toString(); return { url: new URL(`${t}?${c}`), state: a.state, nonce: a.nonce, codeChallenge: a.code_challenge, codeVerifier: d }; }; async function B() { const e = P(52), r = new TextEncoder().encode(e); let n = ""; if (!crypto) n = A(btoa(e)); else { const o = await crypto.subtle.digest("SHA-256", r); n = A(o); } return { codeVerifier: e, codeChallenge: n }; } let S; function V(e, r) { if (b(), typeof window > "u") throw new Error("setRefreshTimer requires a browser environment"); if (e <= 0) throw new Error("Timer duration must be positive"); S = window.setTimeout( r, Math.min(e * 1e3 - 1e4, 864e5) ); } function b() { S !== void 0 && (window.clearTimeout(S), S = void 0); } const y = { framework: "", frameworkVersion: "", sdkVersion: "" }, N = async () => { await T()?.removeItems( s.state, s.nonce, s.codeVerifier ); }, ne = async ({ urlParams: e, domain: r, clientId: n, redirectURL: o, autoRefresh: t = !1, onRefresh: u }) => { const a = e.get("state"), d = e.get("code"); if (!a || !d) return console.error("Invalid state or code"), { success: !1, error: "Invalid state or code" }; const c = T(); if (!c) return console.error("No active storage found"), { success: !1, error: "Authentication storage is not initialized" }; (!y.framework || !y.frameworkVersion) && console.warn( "Framework and version not set. Please set the framework and version in the config object" ); const l = await c.getSessionItem(s.state); if (a !== l) return console.error("Invalid state"), { success: !1, error: `Invalid state; supplied ${a}, expected ${l}` }; const h = await c.getSessionItem( s.codeVerifier ); if (h === null) return console.error("Code verifier not found"), { success: !1, error: "Code verifier not found" }; const E = { "Content-type": "application/x-www-form-urlencoded; charset=UTF-8" }; y.framework && (E["Kinde-SDK"] = `${y.framework}/${y.sdkVersion}/${y.frameworkVersion}/Javascript`); const O = { method: "POST", ...!i.useInsecureForRefreshToken && $(r) ? { credentials: "include" } : {}, headers: new Headers(E), body: new URLSearchParams({ client_id: n, code: d, code_verifier: h, grant_type: "authorization_code", redirect_uri: o }) }; let w; b(); try { if (w = await fetch(`${r}/oauth2/token`, O), !w?.ok) { const g = await w.text(); return console.error("Token exchange failed:", w.status, g), { success: !1, error: `Token exchange failed: ${w.status} - ${g}` }; } } catch (g) { return N(), console.error("Token exchange failed:", g), { success: !1, error: `Token exchange failed: ${g}` }; } const f = await w.json(), L = _(); L && L.setItems({ [s.accessToken]: f.access_token, [s.idToken]: f.id_token, [s.refreshToken]: f.refresh_token }), (i.useInsecureForRefreshToken || !$(r)) && c.setSessionItem(s.refreshToken, f.refresh_token), t && V(f.expires_in, async () => { I({ domain: r, clientId: n, onRefresh: u }); }), N(); const M = ((g) => (g.search = "", g))(new URL(window.location.toString())); return window.history.replaceState(window.history.state, "", M), !f.access_token || !f.id_token || !f.refresh_token ? { success: !1, error: "No access token received" } : { success: !0, [s.accessToken]: f.access_token, [s.idToken]: f.id_token, [s.refreshToken]: f.refresh_token }; }; function Z(e) { const r = document.cookie.split("; ").find((n) => n.startsWith(`${e}=`)); if (!r) return null; try { const n = r.split("=")[1]; return n ? decodeURIComponent(n) : null; } catch (n) { return console.error(`Error parsing cookie ${e}:`, n), null; } } const Q = "_kbrte", oe = async ({ domain: e, clientId: r }) => { if (!e) return { success: !1, error: "Domain is required for authentication check" }; if (!r) return { success: !1, error: "Client ID is required for authentication check" }; const n = $(e), o = i.useInsecureForRefreshToken; let t = null; return n && !o && (t = Z(Q)), await I({ domain: e, clientId: r, refreshType: t ? p.cookie : p.refreshToken }); }, $ = (e) => !e.match( /^(?:https?:\/\/)?[a-zA-Z0-9][.-a-zA-Z0-9]*\.kinde\.com$/i ); function U(e, r) { return r <= 0 ? [] : e.match(new RegExp(`.{1,${r}}`, "g")) || []; } var s = /* @__PURE__ */ ((e) => (e.accessToken = "accessToken", e.idToken = "idToken", e.refreshToken = "refreshToken", e.state = "state", e.nonce = "nonce", e.codeVerifier = "codeVerifier", e))(s || {}); class z { async setItems(r) { await Promise.all( Object.entries(r).map( ([n, o]) => this.setSessionItem(n, o) ) ); } async removeItems(...r) { await Promise.all( r.map((n) => this.removeSessionItem(n)) ); } } class te extends z { memCache = {}; /** * Clears all items from session store. * @returns {void} */ async destroySession() { this.memCache = {}; } /** * Sets the provided key-value store to the memory cache. * @param {string} itemKey * @param {unknown} itemValue * @returns {void} */ async setSessionItem(r, n) { if (await this.removeSessionItem(r), typeof n == "string") { U(n, i.maxLength).forEach( (o, t) => { this.memCache[`${i.keyPrefix}${r}${t}`] = o; } ); return; } this.memCache[`${i.keyPrefix}${String(r)}0`] = n; } /** * Gets the item for the provided key from the memory cache. * @param {string} itemKey * @returns {unknown | null} */ async getSessionItem(r) { if (this.memCache[`${i.keyPrefix}${String(r)}0`] === void 0) return null; let n = "", o = 0, t = `${i.keyPrefix}${String(r)}${o}`; for (; this.memCache[t] !== void 0; ) n += this.memCache[t], o++, t = `${i.keyPrefix}${String(r)}${o}`; return n; } /** * Removes the item for the provided key from the memory cache. * @param {string} itemKey * @returns {void} */ async removeSessionItem(r) { for (const n in this.memCache) n.startsWith(`${i.keyPrefix}${String(r)}`) && delete this.memCache[n]; } } function v(e) { return new Promise((r, n) => { chrome.storage.local.get([e], function(o) { chrome.runtime.lastError ? n(void 0) : r(o[e]); }); }); } class se extends z { /** * Clears all items from session store. * @returns {void} */ async destroySession() { await chrome.storage.local.clear(); } /** * Sets the provided key-value store to the chrome.store.local. * @param {string} itemKey * @param {unknown} itemValue * @returns {void} */ async setSessionItem(r, n) { if (await this.removeSessionItem(r), typeof n == "string") { U(n, i.maxLength).forEach( async (o, t) => { await chrome.storage.local.set({ [`${i.keyPrefix}${r}${t}`]: o }); } ); return; } await chrome.storage.local.set({ [`${i.keyPrefix}${r}0`]: n }); } /** * Gets the item for the provided key from the chrome.store.local cache. * @param {string} itemKey * @returns {unknown | null} */ async getSessionItem(r) { let n = "", o = 0, t = `${i.keyPrefix}${String(r)}${o}`; for (; await v( `${i.keyPrefix}${String(r)}${o}` ) !== void 0; ) n += await v(t), o++, t = `${i.keyPrefix}${String(r)}${o}`; return n; } /** * Removes the item for the provided key from the chrome.store.local cache. * @param {string} itemKey * @returns {void} */ async removeSessionItem(r) { let n = 0; for (; await v( `${i.keyPrefix}${String(r)}${n}` ) !== void 0; ) await chrome.storage.local.remove( `${i.keyPrefix}${String(r)}${n}` ), n++; } } class ae extends z { constructor() { super(), i.useInsecureForRefreshToken && console.warn("LocalStorage store should not be used in production"); } internalItems = /* @__PURE__ */ new Set(); /** * Clears all items from session store. * @returns {void} */ async destroySession() { this.internalItems.forEach((r) => { this.removeSessionItem(r); }); } /** * Sets the provided key-value store to the localStorage cache. * @param {V} itemKey * @param {unknown} itemValue * @returns {void} */ async setSessionItem(r, n) { if (await this.removeSessionItem(r), this.internalItems.add(r), typeof n == "string") { U(n, i.maxLength).forEach( (o, t) => { localStorage.setItem( `${i.keyPrefix}${r}${t}`, o ); } ); return; } localStorage.setItem( `${i.keyPrefix}${r}0`, n ); } /** * Gets the item for the provided key from the localStorage cache. * @param {string} itemKey * @returns {unknown | null} */ async getSessionItem(r) { if (localStorage.getItem(`${i.keyPrefix}${r}0`) === null) return null; let n = "", o = 0, t = `${i.keyPrefix}${String(r)}${o}`; for (; localStorage.getItem(t) !== null; ) n += localStorage.getItem(t), o++, t = `${i.keyPrefix}${String(r)}${o}`; return n; } /** * Removes the item for the provided key from the localStorage cache. * @param {V} itemKey * @returns {void} */ async removeSessionItem(r) { let n = 0; for (; localStorage.getItem( `${i.keyPrefix}${String(r)}${n}` ) !== null; ) localStorage.removeItem( `${i.keyPrefix}${String(r)}${n}` ), n++; this.internalItems.delete(r); } } const i = { /** * The prefix to use for the storage keys. */ keyPrefix: "kinde-", /** * The maximum length of the storage. * * If the length is exceeded the items will be split into multiple storage items. */ maxLength: 2e3, /** * Use insecure storage for refresh token. * * Warning: This should only be used when you're not using a custom domain and no backend app to authenticate on. */ useInsecureForRefreshToken: !1 }; function X(e, r) { if (!e) return null; const n = e.split("."); if (n.length !== 3) return null; const o = n[ 1 /* body */ ].replace(/-/g, "+").replace(/_/g, "/"), t = decodeURIComponent( atob(o).split("").map((u) => "%" + ("00" + u.charCodeAt(0).toString(16)).slice(-2)).join("") ); return JSON.parse(t); } const k = async (e = s.accessToken) => { const r = _(); if (!r) return null; const n = await r.getSessionItem( e === "accessToken" ? s.accessToken : s.idToken ); if (!n) return null; const o = X(n); return o || console.warn("No decoded token found"), o; }, F = async (e = "accessToken") => k(e), ie = async (e, r = "accessToken") => { const n = await F(r); return n ? { name: e, value: n[e] } : null; }, ce = async () => { const e = await k(); return e ? e.org_code || e["x-hasura-org-code"] : null; }, le = async (e = s.accessToken) => { const r = _(); return r && await r.getSessionItem( e === "accessToken" ? s.accessToken : s.idToken ) || null; }, ue = async (e) => { const r = await k(); if (!r) return null; const n = r.feature_flags || r["x-hasura-feature-flags"]; return n ? n[e]?.v ?? null : null; }, de = async () => { const e = await F("idToken"); if (!e) return null; const { sub: r } = e; return r ? { id: e.sub, givenName: e.given_name, familyName: e.family_name, email: e.email, picture: e.picture } : (console.error("No sub in idToken"), null); }, fe = async (e) => { const r = await k(); if (!r) return { permissionKey: e, orgCode: null, isGranted: !1 }; const n = r.permissions || []; return { permissionKey: e, orgCode: r.org_code, isGranted: !!n.includes(e) }; }, he = async () => { const e = await k(); if (!e) return { orgCode: null, permissions: [] }; const r = e.permissions || e["x-hasura-permissions"] || []; return { orgCode: e.org_code || e["x-hasura-org-code"], permissions: r }; }, me = async () => { const e = await k("idToken"); return e ? !e.org_codes && !e["x-hasura-org-codes"] ? (console.warn( "Org codes not found in token, ensure org codes have been included in the token customisation within the application settings" ), null) : e.org_codes || e["x-hasura-org-codes"] : null; }, ge = async () => { const e = await k(); return e ? !e.roles && !e["x-hasura-roles"] ? (console.warn( "No roles found in token, ensure roles have been included in the token customisation within the application settings" ), []) : e.roles || e["x-hasura-roles"] : []; }, ke = async (e) => { try { const r = await k("accessToken"); if (!r) return !1; if (!r.exp) return console.error("Token does not have an expiry"), !1; const n = r.exp < Math.floor(Date.now() / 1e3); return n && e?.useRefreshToken ? (await I({ domain: e.domain, clientId: e.clientId })).success : !n; } catch (r) { return console.error("Error checking authentication:", r), !1; } }, I = async ({ domain: e, clientId: r, refreshType: n = p.refreshToken, onRefresh: o }) => { const t = (d) => (o && o(d), d); if (!e) return t({ success: !1, error: "Domain is required for token refresh" }); if (!r) return t({ success: !1, error: "Client ID is required for token refresh" }); let u = "", a; if (i.useInsecureForRefreshToken || !$(e) ? a = T() : a = _(), n === p.refreshToken) { if (!a) return t({ success: !1, error: "No active storage found" }); if (u = await a.getSessionItem( s.refreshToken ), !u) return t({ success: !1, error: "No refresh token found" }); } b(); try { const d = await fetch(`${R(e)}/oauth2/token`, { method: "POST", ...n === p.cookie && { credentials: "include" }, headers: { "Content-type": "application/x-www-form-urlencoded; charset=UTF-8" }, body: new URLSearchParams({ ...n === p.refreshToken && { refresh_token: u }, grant_type: "refresh_token", client_id: r }).toString() }); if (!d.ok) return t({ success: !1, error: "Failed to refresh token" }); const c = await d.json(); if (c.access_token) { const l = _(); return l ? (V(c.expires_in, async () => { I({ domain: e, clientId: r, refreshType: n, onRefresh: o }); }), a && (await l.setSessionItem( s.accessToken, c.access_token ), c.id_token && await l.setSessionItem(s.idToken, c.id_token), c.refresh_token && await a.setSessionItem( s.refreshToken, c.refresh_token )), t({ success: !0, [s.accessToken]: c.access_token, [s.idToken]: c.id_token, [s.refreshToken]: c.refresh_token })) : t({ success: !1, error: "No active storage found" }); } } catch (d) { return t({ success: !1, error: `No access token received: ${d}` }); } return t({ success: !1, error: "No access token received" }); }, m = { secure: null, insecure: null }, pe = (e) => { m.secure = e; }, _ = () => m.secure || null, we = () => m.secure !== null, ye = () => { m.secure = null; }, _e = (e) => { m.insecure = e; }, T = () => m.insecure || m.secure || null, Se = () => m.insecure !== null, $e = () => { m.insecure = null; }, Ie = async (e) => (console.warn( "Warning: generateProfileUrl is deprecated. Please use generatePortalUrl instead." ), Y({ domain: e.domain, returnUrl: e.returnUrl, subNav: e.subNav })), Y = async ({ domain: e, returnUrl: r, subNav: n }) => { const o = _(); if (!o) throw new Error("generatePortalUrl: Active storage not found"); const t = await o.getSessionItem( s.accessToken ); if (!t) throw new Error("generatePortalUrl: Access Token not found"); const u = new URLSearchParams({ sub_nav: n || D.profile, return_url: r }), a = await fetch( `${R(e)}/account_api/v1/portal_link?${u.toString()}`, { headers: { Authorization: `Bearer ${t}` } } ); if (!a.ok) throw new Error( `Failed to fetch profile URL: ${a.status} ${a.statusText}` ); const d = await a.json(); if (!d.url || typeof d.url != "string") throw new Error("Invalid URL received from API"); try { return { url: new URL(d.url) }; } catch (c) { throw console.error(c), new Error(`Invalid URL format received from API: ${d.url}`); } }, Te = { __esModule: !0, default: async () => (await import("./expoSecureStore-XvKE_bbE-CtT94rTt.js")).ExpoSecureStore }; export { I as $, z as A, J as B, P as C, T as D, le as E, we as F, Se as G, q as H, x as I, $ as J, Y as K, A as L, F as M, j as N, H as O, R as P, V as Q, b as R, ke as S, $e as T, D as V, pe as _, s as a, U as b, i as c, te as d, y as e, ue as f, fe as g, de as h, ae as i, se as j, me as k, ie as l, he as m, re as n, ne as o, _ as p, Te as q, p as r, oe as s, ee as t, ce as u, ye as v, ge as w, Ie as x, _e as y, k as z };