@scalar/api-client
Version:
the open source API testing client
131 lines (130 loc) • 5.8 kB
JavaScript
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
};