"use client"; /* eslint-disable react-hooks/exhaustive-deps */ import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useState, useEffect } from "react"; import { APP_NAME } from "@calcom/lib/constants"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Avatar } from "@calcom/ui/components/avatar"; import { Button } from "@calcom/ui/components/button"; import { Select } from "@calcom/ui/components/form"; import { Icon } from "@calcom/ui/components/icon"; export default function Authorize() { const { t } = useLocale(); const { status } = useSession(); const router = useRouter(); const searchParams = useCompatSearchParams(); const client_id = (searchParams?.get("client_id") as string) || ""; const state = searchParams?.get("state") as string; const scope = searchParams?.get("scope") as string; const code_challenge = searchParams?.get("code_challenge") as string; const code_challenge_method = searchParams?.get("code_challenge_method") as string; const queryString = searchParams?.toString(); const [selectedAccount, setSelectedAccount] = useState<{ value: string; label: string } | null>(); const scopes = scope ? scope.toString().split(",") : []; const { data: client, isPending: isPendingGetClient } = trpc.viewer.oAuth.getClient.useQuery( { clientId: client_id as string, }, { enabled: status !== "loading", } ); const { data, isPending: isPendingProfiles } = trpc.viewer.loggedInViewerRouter.teamsAndUserProfilesQuery.useQuery(); const generateAuthCodeMutation = trpc.viewer.oAuth.generateAuthCode.useMutation({ onSuccess: (data) => { window.location.href = `${client?.redirectUri}?code=${data.authorizationCode}&state=${state}`; }, onError: (error) => { let oauthError = "server_error"; if (error.data?.code === "BAD_REQUEST") { oauthError = "invalid_request"; } else if (error.data?.code === "UNAUTHORIZED") { oauthError = "unauthorized_client"; } const errorParams = new URLSearchParams({ error: oauthError, }); if (error.message) { errorParams.append("error_description", error.message); } if (state) { errorParams.append("state", state); } if (client?.redirectUri) { window.location.href = `${client.redirectUri}${ client.redirectUri.includes("?") ? "&" : "?" }${errorParams.toString()}`; } }, }); const mappedProfiles = data ? data .filter((profile) => !profile.readOnly) .map((profile) => ({ label: profile.name || profile.slug || "", value: profile.slug || "", })) : []; useEffect(() => { if (mappedProfiles.length > 0) { setSelectedAccount(mappedProfiles[0]); } }, [isPendingProfiles]); // Auto-authorize trusted clients useEffect(() => { if (client?.isTrusted && selectedAccount) { generateAuthCodeMutation.mutate({ clientId: client_id as string, scopes, codeChallenge: code_challenge || undefined, codeChallengeMethod: (code_challenge_method as "S256") || undefined, }); } }, [client?.isTrusted, selectedAccount]); useEffect(() => { if (status === "unauthenticated") { const urlSearchParams = new URLSearchParams({ callbackUrl: `auth/oauth2/authorize?${queryString}`, }); router.replace(`/auth/login?${urlSearchParams.toString()}`); } }, [status]); const isPending = isPendingGetClient || isPendingProfiles || status !== "authenticated"; if (isPending) { return <>; } if (!client) { return
{t("unauthorized")}
; } // Don't show UI for trusted clients, they'll auto-authorize if (client.isTrusted && selectedAccount) { return (
Authorizing...
); } return (
} className="items-center" imageSrc={client.logo} size="lg" />
Logo

{t("access_cal_account", { clientName: client.name, appName: APP_NAME })}

{t("select_account_team")}