import { useUserContext } from "@/context/user-context"; import { useMutation, useQuery } from "@tanstack/react-query"; import { Navigate, useNavigate } from "react-router"; import { useLocation } from "react-router"; import { Card, CardHeader, CardTitle, CardDescription, CardFooter, CardContent, } from "@/components/ui/card"; import { getOidcClientInfoSchema } from "@/schemas/oidc-schemas"; import { Button } from "@/components/ui/button"; import axios from "axios"; import { toast } from "sonner"; import { useOIDCParams } from "@/lib/hooks/oidc"; import { useTranslation } from "react-i18next"; import { TFunction } from "i18next"; import { Mail, Shield, User, Users } from "lucide-react"; type Scope = { id: string; name: string; description: string; icon: React.ReactNode; }; const scopeMapIconProps = { className: "stroke-card stroke-2.5", }; const createScopeMap = (t: TFunction<"translation", undefined>): Scope[] => { return [ { id: "openid", name: t("openidScopeName"), description: t("openidScopeDescription"), icon: , }, { id: "email", name: t("emailScopeName"), description: t("emailScopeDescription"), icon: , }, { id: "profile", name: t("profileScopeName"), description: t("profileScopeDescription"), icon: , }, { id: "groups", name: t("groupsScopeName"), description: t("groupsScopeDescription"), icon: , }, ]; }; export const AuthorizePage = () => { const { isLoggedIn } = useUserContext(); const { search } = useLocation(); const { t } = useTranslation(); const navigate = useNavigate(); const scopeMap = createScopeMap(t); const searchParams = new URLSearchParams(search); const { values: props, missingParams, isOidc, compiled: compiledOIDCParams, } = useOIDCParams(searchParams); const scopes = props.scope ? props.scope.split(" ").filter(Boolean) : []; const getClientInfo = useQuery({ queryKey: ["client", props.client_id], queryFn: async () => { const res = await fetch(`/api/oidc/clients/${props.client_id}`); const data = await getOidcClientInfoSchema.parseAsync(await res.json()); return data; }, enabled: isOidc, }); const authorizeMutation = useMutation({ mutationFn: () => { return axios.post("/api/oidc/authorize", { scope: props.scope, response_type: props.response_type, client_id: props.client_id, redirect_uri: props.redirect_uri, state: props.state, }); }, mutationKey: ["authorize", props.client_id], onSuccess: (data) => { toast.info(t("authorizeSuccessTitle"), { description: t("authorizeSuccessSubtitle"), }); window.location.replace(data.data.redirect_uri); }, onError: (error) => { window.location.replace( `/error?error=${encodeURIComponent(error.message)}`, ); }, }); if (missingParams.length > 0) { return ( ); } if (!isLoggedIn) { return ; } if (getClientInfo.isLoading) { return ( {t("authorizeLoadingTitle")} {t("authorizeLoadingSubtitle")} ); } if (getClientInfo.isError) { return ( ); } return ( {t("authorizeCardTitle", { app: getClientInfo.data?.name || "Unknown", })} {scopes.includes("openid") ? t("authorizeSubtitle") : t("authorizeSubtitleOAuth")} {scopes.includes("openid") && ( {scopes.map((id) => { const scope = scopeMap.find((s) => s.id === id); if (!scope) return null; return (
{scope.icon}
{scope.name}
{scope.description}
); })}
)}
); };