UNPKG

@scalar/api-client

Version:

the open source API testing client

131 lines (130 loc) 5.8 kB
import { isRelativePath as E } from "@scalar/helpers/url/is-relative-path"; import { makeUrlAbsolute as b } from "@scalar/helpers/url/make-url-absolute"; import { shouldUseProxy as S } from "@scalar/helpers/url/redirect-to-proxy"; import { encode as z, fromUint8Array as C } from "js-base64"; const A = (t) => { const e = t?.url; return e ? E(e) ? typeof window > "u" ? {} : { basePath: e } : { baseUrl: e } : {}; }, F = () => { const t = new Uint8Array(32); return crypto.getRandomValues(t), C(t, !0); }, R = async (t, e) => { if (e === "plain") return t; if (typeof crypto?.subtle?.digest != "function") return console.warn("SHA-256 is only supported when using https, using a plain text code challenge instead."), t; const l = new TextEncoder().encode(t), f = await crypto.subtle.digest("SHA-256", l); return C(new Uint8Array(f), !0); }, W = async (t, e, g, l, f) => { const d = t[e]; try { if (!d) return [new Error("Flow not found"), null]; const m = g.join(" "); if (e === "clientCredentials" || e === "password") return U( t, e, m, { proxyUrl: f }, l ); const r = (Math.random() + 1).toString(36).substring(2, 10), a = b(t[e].authorizationUrl, A(l)), n = new URL(a); let c = null; if (e === "implicit") n.searchParams.set("response_type", "token"); else if (e === "authorizationCode") { const s = t[e]; if (n.searchParams.set("response_type", "code"), s["x-usePkce"] !== "no") { const o = F(), u = await R(o, s["x-usePkce"]); c = { codeVerifier: o, codeChallenge: u, codeChallengeMethod: s["x-usePkce"] === "SHA-256" ? "S256" : "plain" }, n.searchParams.set("code_challenge", u), n.searchParams.set("code_challenge_method", c.codeChallengeMethod); } } const i = t[e]; if (i["x-scalar-secret-redirect-uri"].startsWith("/")) { const s = l?.url || window.location.origin + window.location.pathname, o = new URL(i["x-scalar-secret-redirect-uri"], s).toString(); n.searchParams.set("redirect_uri", o); } else n.searchParams.set("redirect_uri", i["x-scalar-secret-redirect-uri"]); d["x-scalar-security-query"] && Object.keys(d["x-scalar-security-query"]).forEach((s) => { const o = d["x-scalar-security-query"]?.[s]; o && n.searchParams.set(s, o); }), n.searchParams.set("client_id", d["x-scalar-secret-client-id"]), n.searchParams.set("state", r), m && n.searchParams.set("scope", m); const h = window.open(n, "openAuth2Window", "left=100,top=100,width=800,height=600"); return h ? new Promise((s) => { const o = setInterval(() => { let u = null, p = null, x = null, _ = null; try { const w = new URL(h.location.href).searchParams, k = d["x-tokenName"] || "access_token"; u = w.get(k), p = w.get("code"), x = w.get("error"), _ = w.get("error_description"); const P = new URLSearchParams(h.location.href.split("#")[1]); u ||= P.get(k), p ||= P.get("code"), x ||= P.get("error"), _ ||= P.get("error_description"); } catch { } if (h.closed || u || p || x) if (clearInterval(o), h.close(), x) s([new Error(`OAuth error: ${x}${_ ? ` (${_})` : ""}`), null]); else if (u) { const w = h.location.href.match(/state=([^&]*)/)?.[1]; s(w === r ? [null, u] : [new Error("State mismatch"), null]); } else p && e === "authorizationCode" ? new URL(h.location.href).searchParams.get("state") === r ? U( t, e, m, { code: p, pkce: c, proxyUrl: f }, l ).then(s) : s([new Error("State mismatch"), null]) : (clearInterval(o), s([new Error("Window was closed without granting authorization"), null])); }, 200); }) : [new Error("Failed to open auth window"), null]; } catch { return [new Error("Failed to authorize oauth2 flow"), null]; } }, U = async (t, e, g, { code: l, pkce: f, proxyUrl: d } = {}, m) => { const r = t[e]; if (!r) return [new Error("OAuth2 flow was not defined"), null]; const a = new URLSearchParams(); g && (e === "clientCredentials" || e === "password") && a.set("scope", g); const n = r["x-scalar-credentials-location"] === "body"; if (n && (a.set("client_id", r["x-scalar-secret-client-id"]), a.set("client_secret", r["x-scalar-secret-client-secret"])), "x-scalar-secret-redirect-uri" in r && r["x-scalar-secret-redirect-uri"] && a.set("redirect_uri", r["x-scalar-secret-redirect-uri"]), l) a.set("code", l), a.set("grant_type", "authorization_code"), f && a.set("code_verifier", f.codeVerifier); else if (e === "password") { const c = t[e]; a.set("grant_type", "password"), a.set("username", c["x-scalar-secret-username"]), a.set("password", c["x-scalar-secret-password"]); } else a.set("grant_type", "client_credentials"); r["x-scalar-security-body"] && Object.entries(r["x-scalar-security-body"]).forEach(([c, i]) => { i && a.set(c, i); }); try { const c = { "Content-Type": "application/x-www-form-urlencoded" }; n || (c.Authorization = `Basic ${z(`${r["x-scalar-secret-client-id"]}:${r["x-scalar-secret-client-secret"]}`)}`); const i = b(r.tokenUrl, A(m)), y = S(d, i) ? `${d}?${new URLSearchParams([["scalar_url", i]]).toString()}` : i, s = await (await fetch(y, { method: "POST", headers: c, body: a })).json(), o = r["x-tokenName"] || "access_token"; return [null, s[o]]; } catch { return [new Error("Failed to get an access token. Please check your credentials."), null]; } }; export { W as authorizeOauth2 };