diff --git a/frontend/src/pages/authorize-page.tsx b/frontend/src/pages/authorize-page.tsx index 730e5f27..261a7da3 100644 --- a/frontend/src/pages/authorize-page.tsx +++ b/frontend/src/pages/authorize-page.tsx @@ -1,5 +1,5 @@ import { useUserContext } from "@/context/user-context"; -import { useMutation } from "@tanstack/react-query"; +import {useMutation} from "@tanstack/react-query"; import { Navigate, useNavigate } from "react-router"; import { useLocation } from "react-router"; import { @@ -25,7 +25,8 @@ import { searchParamsFromObject, useScreenParams, } from "@/lib/hooks/screen-params"; -import { useEffect } from "react"; +import {useEffect, useState} from "react"; +import { z } from "zod"; type Scope = { id: string; @@ -34,6 +35,10 @@ type Scope = { icon: React.ReactNode; }; +const skipConsentResponseSchema = z.object({ + skipConsent: z.boolean(), +}) + const scopeMapIconProps = { className: "stroke-muted-foreground stroke-[1.75] h-4", }; @@ -96,14 +101,8 @@ export const AuthorizePage = () => { } return ""; })(); - - // TODO: maybe a better way to do this - const shouldAutoAuthorize = - auth.authenticated && - isOidc && - screenParams.oidc_ticket !== undefined && - screenParams.oidc_scope !== undefined && - screenParams.oidc_prompt === "none"; + const [autoAuthorize, setAutoAuthorize] = useState(false); + const [skipConsentChecked, setSkipConsentChecked] = useState(false); const { mutate: authorizeMutate, isPending: authorizePending } = useMutation({ mutationFn: () => { @@ -126,10 +125,34 @@ export const AuthorizePage = () => { }); useEffect(() => { - if (shouldAutoAuthorize) { - authorizeMutate(); - } - }, [shouldAutoAuthorize, authorizeMutate]); + let active = true; + const controller = new AbortController(); + + const checkSkipConsent = async () => { + try { + const res = await fetch( + `/api/oidc/skip-consent?oidc_ticket=${encodeURIComponent( screenParams.oidc_ticket ?? "")}`, + { signal: controller.signal }, + ); + if (!res.ok) return; + const parsed = skipConsentResponseSchema.safeParse(await res.json()); + if (!active || !parsed.success || !parsed.data.skipConsent) return; + setAutoAuthorize(true); + authorizeMutate(); + } catch { + // Fall back to manual consent on any failure (including abort). + } finally { + if (active) setSkipConsentChecked(true); + } + }; + + checkSkipConsent(); + + return () => { + active = false; + controller.abort(); + }; + }, [authorizeMutate, screenParams.oidc_ticket]); if (!isOidc || !screenParams.oidc_ticket || !screenParams.oidc_scope) { return ( @@ -190,13 +213,13 @@ export const AuthorizePage = () => {