@scalar/api-client
Version:
the open source API testing client
100 lines (99 loc) • 5.29 kB
JavaScript
import { shouldUseProxy as S } from "@scalar/oas-utils/helpers";
const k = () => {
const e = new Uint8Array(32);
return crypto.getRandomValues(e), btoa(String.fromCharCode(...e)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}, C = async (e, l) => {
if (l === "plain")
return e;
const n = new TextEncoder().encode(e), i = await crypto.subtle.digest("SHA-256", n);
return btoa(String.fromCharCode(...new Uint8Array(i))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}, b = async (e, l, u) => {
try {
if (!e)
return [new Error("Flow not found"), null];
const n = e.selectedScopes.join(" ");
if (e.type === "clientCredentials" || e.type === "password")
return P(e, n, {
proxyUrl: u
});
const i = (Math.random() + 1).toString(36).substring(2, 10), t = new URL(e.authorizationUrl);
let m = null;
if (e.type === "implicit")
t.searchParams.set("response_type", "token");
else if (e.type === "authorizationCode" && (t.searchParams.set("response_type", "code"), e["x-usePkce"] !== "no")) {
const r = k(), s = await C(r, e["x-usePkce"]);
m = {
codeVerifier: r,
codeChallenge: s,
codeChallengeMethod: e["x-usePkce"] === "SHA-256" ? "S256" : "plain"
}, t.searchParams.set("code_challenge", s), t.searchParams.set("code_challenge_method", m.codeChallengeMethod);
}
if (e["x-scalar-redirect-uri"].startsWith("/")) {
const r = l.url || window.location.origin + window.location.pathname, s = new URL(e["x-scalar-redirect-uri"], r).toString();
t.searchParams.set("redirect_uri", s);
} else
t.searchParams.set("redirect_uri", e["x-scalar-redirect-uri"]);
e["x-scalar-security-query"] && Object.keys(e["x-scalar-security-query"]).forEach((r) => {
var c;
const s = (c = e["x-scalar-security-query"]) == null ? void 0 : c[r];
s && t.searchParams.set(r, s);
}), t.searchParams.set("client_id", e["x-scalar-client-id"]), t.searchParams.set("state", i), n && t.searchParams.set("scope", n);
const a = window.open(t, "openAuth2Window", "left=100,top=100,width=800,height=600");
return a ? new Promise((r) => {
const s = setInterval(() => {
var _;
let c = null, d = null, h = null, g = null;
try {
const o = new URL(a.location.href).searchParams, x = e["x-tokenName"] || "access_token";
c = o.get(x), d = o.get("code"), h = o.get("error"), g = o.get("error_description");
const y = new URLSearchParams(a.location.href.split("#")[1]);
c || (c = y.get(x)), d || (d = y.get("code")), h || (h = y.get("error")), g || (g = y.get("error_description"));
} catch {
}
if (a.closed || c || d || h)
if (clearInterval(s), a.close(), h)
r([new Error(`OAuth error: ${h}${g ? ` (${g})` : ""}`), null]);
else if (c) {
const o = (_ = a.location.href.match(/state=([^&]*)/)) == null ? void 0 : _[1];
r(o === i ? [null, c] : [new Error("State mismatch"), null]);
} else d ? new URL(a.location.href).searchParams.get("state") === i ? P(e, n, {
code: d,
pkce: m,
proxyUrl: u
}).then(r) : r([new Error("State mismatch"), null]) : (clearInterval(s), r([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];
}
}, P = async (e, l, {
code: u,
pkce: n,
proxyUrl: i
} = {}) => {
if (!e)
return [new Error("OAuth2 flow was not defined"), null];
const t = new URLSearchParams();
t.set("client_id", e["x-scalar-client-id"]), l && (e.type === "clientCredentials" || e.type === "password") && t.set("scope", l), e.clientSecret && (!e["x-scalar-credentials-location"] || e["x-scalar-credentials-location"] === "body") && t.set("client_secret", e.clientSecret), "x-scalar-redirect-uri" in e && e["x-scalar-redirect-uri"] && t.set("redirect_uri", e["x-scalar-redirect-uri"]), u ? (t.set("code", u), t.set("grant_type", "authorization_code"), n && t.set("code_verifier", n.codeVerifier)) : e.type === "password" ? (t.set("grant_type", "password"), t.set("username", e.username), t.set("password", e.password)) : t.set("grant_type", "client_credentials"), e["x-scalar-security-body"] && Object.entries(e["x-scalar-security-body"]).forEach(([p, a]) => {
a && t.set(p, a);
});
try {
const p = {
"Content-Type": "application/x-www-form-urlencoded"
};
e.clientSecret && (!e["x-scalar-credentials-location"] || e["x-scalar-credentials-location"] === "header") && (p.Authorization = `Basic ${btoa(`${e["x-scalar-client-id"]}:${e.clientSecret}`)}`);
const r = S(i, e.tokenUrl) ? `${i}?${new URLSearchParams([["scalar_url", e.tokenUrl]]).toString()}` : e.tokenUrl, c = await (await fetch(r, {
method: "POST",
headers: p,
body: t
})).json(), d = e["x-tokenName"] || "access_token";
return [null, c[d]];
} catch {
return [new Error("Failed to get an access token. Please check your credentials."), null];
}
};
export {
b as authorizeOauth2,
P as authorizeServers,
C as generateCodeChallenge
};