import { AuthDebuggerState, OAuthStep } from "@/lib/auth-types";
import { CheckCircle2, Circle, ExternalLink } from "lucide-react";
import { Button } from "./ui/button";
import { DebugInspectorOAuthClientProvider } from "@/lib/auth";
interface OAuthStepProps {
label: string;
isComplete: boolean;
isCurrent: boolean;
error?: Error | null;
children?: React.ReactNode;
}
const OAuthStepDetails = ({
label,
isComplete,
isCurrent,
error,
children,
}: OAuthStepProps) => {
return (
{isComplete ? (
) : (
)}
{label}
{/* Show children if current step or complete and children exist */}
{(isCurrent || isComplete) && children && (
{children}
)}
{/* Display error if current step and an error exists */}
{isCurrent && error && (
)}
);
};
interface OAuthFlowProgressProps {
serverUrl: string;
authState: AuthDebuggerState;
updateAuthState: (updates: Partial) => void;
proceedToNextStep: () => Promise;
}
export const OAuthFlowProgress = ({
serverUrl,
authState,
updateAuthState,
proceedToNextStep,
}: OAuthFlowProgressProps) => {
const provider = new DebugInspectorOAuthClientProvider(serverUrl);
const steps: Array = [
"metadata_discovery",
"client_registration",
"authorization_redirect",
"authorization_code",
"token_request",
"complete",
];
const currentStepIdx = steps.findIndex((s) => s === authState.oauthStep);
// Helper to get step props
const getStepProps = (stepName: OAuthStep) => ({
isComplete:
currentStepIdx > steps.indexOf(stepName) ||
currentStepIdx === steps.length - 1, // last step is "complete"
isCurrent: authState.oauthStep === stepName,
error: authState.oauthStep === stepName ? authState.latestError : null,
});
return (
OAuth Flow Progress
Follow these steps to complete OAuth authentication with the server.
{provider.getServerMetadata() && (
Retrieved OAuth Metadata from {serverUrl}
/.well-known/oauth-authorization-server
{JSON.stringify(provider.getServerMetadata(), null, 2)}
)}
{authState.oauthClientInfo && (
Registered Client Information
{JSON.stringify(authState.oauthClientInfo, null, 2)}
)}
{authState.authorizationUrl && (
Authorization URL:
{authState.authorizationUrl}
Click the link to authorize in your browser. After
authorization, you'll be redirected back to continue the flow.
)}
{
updateAuthState({
authorizationCode: e.target.value,
validationError: null,
});
}}
placeholder="Enter the code from the authorization server"
className={`flex h-9 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ${
authState.validationError ? "border-red-500" : "border-input"
}`}
/>
{authState.validationError && (
{authState.validationError}
)}
Once you've completed authorization in the link, paste the code
here.
{authState.oauthMetadata && (
Token Request Details
Token Endpoint:
{authState.oauthMetadata.token_endpoint}
)}
{authState.oauthTokens && (
Access Tokens
Authentication successful! You can now use the authenticated
connection. These tokens will be used automatically for server
requests.
{JSON.stringify(authState.oauthTokens, null, 2)}
)}
{authState.oauthStep !== "complete" && (
<>
>
)}
{authState.oauthStep === "authorization_redirect" &&
authState.authorizationUrl && (
)}
);
};