fumadocs-openapi
Version:
Generate MDX docs for your OpenAPI spec
273 lines (271 loc) • 9.55 kB
JavaScript
import { cn } from "../../utils/cn.js";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
import { Input, labelVariants } from "../../ui/components/input.js";
import { useQuery } from "../../utils/use-query.js";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
import { buttonVariants } from "fumadocs-ui/components/ui/button";
//#region src/playground/components/oauth-dialog.tsx
const FlowTypes = {
password: {
name: "Resource Owner Password Flow",
description: "Authenticate using username and password."
},
clientCredentials: {
name: "Client Credentials",
description: "Intended for the server-to-server authentication."
},
authorizationCode: {
name: "Authorization code",
description: "Authenticate with 3rd party services"
},
implicit: {
name: "Implicit",
description: "Retrieve the access token directly."
}
};
function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
const [type, setType] = useState(() => {
return Object.keys(scheme.flows)[0];
});
const form = useForm({ defaultValues: {
clientId: "",
clientSecret: "",
username: "",
password: ""
} });
const authCodeCallback = useQuery(async (code, state) => {
const value = scheme.flows.authorizationCode;
const res = await fetch(value.tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: state.redirect_uri,
client_id: state.client_id,
client_secret: state.client_secret
})
});
if (!res.ok) throw new Error(await res.text());
const { access_token, token_type = "Bearer" } = await res.json();
setToken(`${token_type} ${access_token}`);
setOpen(false);
});
useEffect(() => {
if (scheme.flows.authorizationCode) {
const params = new URLSearchParams(window.location.search);
const state = params.get("state");
const code = params.get("code");
if (state && code) {
const parsedState = JSON.parse(state);
setOpen(true);
form.setValue("clientId", parsedState.client_id);
form.setValue("clientSecret", parsedState.client_secret);
authCodeCallback.start(code, parsedState);
window.history.replaceState(null, "", window.location.pathname);
return;
}
}
if (scheme.flows.implicit && window.location.hash.length > 1) {
const params = new URLSearchParams(window.location.hash.slice(1));
const state = params.get("state");
const token = params.get("access_token");
const type$1 = params.get("token_type") ?? "Bearer";
if (state && token) {
const parsedState = JSON.parse(state);
form.setValue("clientId", parsedState.client_id);
setToken(`${type$1} ${token}`);
window.history.replaceState(null, "", window.location.pathname);
}
}
}, []);
const authorize = useQuery(async (values) => {
if (type === "implicit") {
const value = scheme.flows[type];
const params = new URLSearchParams();
params.set("response_type", "token");
params.set("client_id", values.clientId);
params.set("redirect_uri", window.location.href);
params.set("scope", scopes.join("+"));
params.set("state", JSON.stringify({
client_id: values.clientId,
redirect_uri: window.location.href
}));
window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
return;
}
if (type === "authorizationCode") {
const value = scheme.flows[type];
const params = new URLSearchParams();
params.set("response_type", "code");
params.set("client_id", values.clientId);
params.set("redirect_uri", window.location.href);
params.set("scope", scopes.join("+"));
params.set("state", JSON.stringify({
client_id: values.clientId,
client_secret: values.clientSecret,
redirect_uri: window.location.href
}));
window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
return;
}
let res;
if (type === "password") {
const value = scheme.flows[type];
res = await fetch(value.tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "password",
username: values.username,
password: values.password,
scope: scopes.join("+")
})
});
}
if (type === "clientCredentials") {
const value = scheme.flows[type];
res = await fetch(value.tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: values.clientId,
client_secret: values.clientSecret,
scope: scopes.join("+")
})
});
}
if (res) {
if (!res.ok) throw new Error(await res.text());
const { access_token, token_type = "Bearer" } = await res.json();
setToken(`${token_type} ${access_token}`);
setOpen(false);
}
});
const onSubmit = form.handleSubmit((values) => {
return authorize.start(values);
});
const isLoading = authorize.isLoading || authCodeCallback.isLoading;
const error = authCodeCallback.error ?? authorize.error;
return /* @__PURE__ */ jsxs(Dialog, {
open,
onOpenChange: setOpen,
children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Authorization" }), /* @__PURE__ */ jsx(DialogDescription, { children: "Obtain the access token for API." })] }), /* @__PURE__ */ jsxs("form", {
className: "flex flex-col gap-6",
onSubmit: (e) => {
onSubmit(e);
e.stopPropagation();
},
children: [
/* @__PURE__ */ jsxs(Select, {
value: type,
onValueChange: setType,
children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(scheme.flows).map((key) => {
const { name, description } = FlowTypes[key];
return /* @__PURE__ */ jsxs(SelectItem, {
value: key,
children: [/* @__PURE__ */ jsx("p", {
className: "font-medium",
children: name
}), /* @__PURE__ */ jsx("p", {
className: "text-fd-muted-foreground",
children: description
})]
}, key);
}) })]
}),
(type === "authorizationCode" || type === "clientCredentials" || type === "implicit") && /* @__PURE__ */ jsxs("fieldset", {
className: "flex flex-col gap-1.5",
children: [
/* @__PURE__ */ jsx("label", {
htmlFor: "client_id",
className: cn(labelVariants()),
children: "Client ID"
}),
/* @__PURE__ */ jsx("p", {
className: "text-fd-muted-foreground text-sm",
children: "The client ID of your OAuth application."
}),
/* @__PURE__ */ jsx(Input, {
id: "client_id",
placeholder: "Enter value",
type: "text",
autoComplete: "off",
disabled: isLoading,
...form.register("clientId", { required: true })
})
]
}),
(type === "authorizationCode" || type === "clientCredentials") && /* @__PURE__ */ jsxs("fieldset", {
className: "flex flex-col gap-1.5",
children: [
/* @__PURE__ */ jsx("label", {
htmlFor: "client_secret",
className: cn(labelVariants()),
children: "Client Secret"
}),
/* @__PURE__ */ jsx("p", {
className: "text-fd-muted-foreground text-sm",
children: "The client secret of your OAuth application."
}),
/* @__PURE__ */ jsx(Input, {
id: "client_secret",
placeholder: "Enter value",
type: "password",
autoComplete: "off",
disabled: isLoading,
...form.register("clientSecret", { required: true })
})
]
}),
type === "password" && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("fieldset", {
className: "flex flex-col gap-1.5",
children: [/* @__PURE__ */ jsx("label", {
htmlFor: "username",
className: cn(labelVariants()),
children: "Username"
}), /* @__PURE__ */ jsx(Input, {
id: "username",
placeholder: "Enter value",
type: "text",
disabled: isLoading,
autoComplete: "off",
...form.register("username", { required: true })
})]
}), /* @__PURE__ */ jsxs("fieldset", {
className: "flex flex-col gap-1.5",
children: [/* @__PURE__ */ jsx("label", {
htmlFor: "password",
className: cn(labelVariants()),
children: "Client Secret"
}), /* @__PURE__ */ jsx(Input, {
id: "password",
placeholder: "Enter value",
type: "password",
autoComplete: "off",
disabled: isLoading,
...form.register("password", { required: true })
})]
})] }),
error ? /* @__PURE__ */ jsx("p", {
className: "text-red-400 font-medium text-sm",
children: String(error)
}) : null,
/* @__PURE__ */ jsx("button", {
type: "submit",
disabled: isLoading,
className: cn(buttonVariants({ color: "primary" })),
children: authCodeCallback.isLoading ? "Fetching token..." : "Submit"
})
]
})] })]
});
}
const OauthDialogTrigger = DialogTrigger;
//#endregion
export { OauthDialog, OauthDialogTrigger };
//# sourceMappingURL=oauth-dialog.js.map