'use client' import type { FC } from 'react' import { useEffect, useState } from 'react' import type { ApprovalContext } from '@/service/device-flow' import { approveExternal, fetchApprovalContext } from '@/service/device-flow' import { approveErrorCopy } from '../utils/error-copy' type Props = { onApproved: () => void onError: (message: string) => void } /** * AuthorizeSSO is the external-SSO branch authorize screen. On mount it * fetches /openapi/v1/oauth/device/approval-context to learn subject_email, * issuer, user_code, and csrf_token from the device_approval_grant cookie. * On Approve click, posts /openapi/v1/oauth/device/approve-external with * the CSRF header. * * The user_code in state is bound to the cookie by server; we do not accept * one from the URL because the SSO branch deliberately detaches from the * pre-SSO ?user_code=... query param. */ const AuthorizeSSO: FC = ({ onApproved, onError }) => { const [ctx, setCtx] = useState(null) const [busy, setBusy] = useState(false) const [loadErr, setLoadErr] = useState(null) useEffect(() => { let cancelled = false fetchApprovalContext() .then((c) => { if (!cancelled) setCtx(c) }) .catch((e) => { if (!cancelled) setLoadErr(approveErrorCopy(e)) }) return () => { cancelled = true } }, []) const approve = async () => { if (!ctx) return setBusy(true) try { await approveExternal(ctx, ctx.user_code) onApproved() } catch (e) { onError(approveErrorCopy(e)) } finally { setBusy(false) } } if (loadErr) { return (

This session is no longer valid

Run difyctl auth login again to start a new sign-in.

) } if (!ctx) { return
Loading session…
} return (

Authorize Dify CLI

Dify CLI (difyctl) is requesting access via SSO. If you did not start this from your terminal, close this tab.

Signed in as {ctx.subject_email}

Issuer: {ctx.subject_issuer}

) } export default AuthorizeSSO