@kinde-oss/kinde-auth-react
Version:
Kinde React SDK for authentication
817 lines (816 loc) • 22.7 kB
JavaScript
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
};