Login with ChatGPT
Reference

React

The LoginWithChatGPT widget, the useLoginWithChatGPT hook, and the consent popup helper.

@opencoredev/loginwithchatgpt-react ships two layers over the same state machine: a drop-in widget and a hook for custom UIs. Both are client components and require a mounted server handler.

<LoginWithChatGPT />

components/sign-in.tsx
"use client";

import { LoginWithChatGPT } from "@opencoredev/loginwithchatgpt-react";

export function SignIn() {
  return (
    <LoginWithChatGPT
      consent={{ appName: "Acme", securityHref: "https://acme.dev/security" }}
      onAuthenticated={(user) => console.log("connected", user?.email)}
      onError={(error) => console.error(error)}
    />
  );
}

Props

Accepts every hook option plus:

PropTypeDefaultNotes
labelstring"Login with ChatGPT"Initial button label.
consent{ appName?, continueLabel?, securityHref? }{}Customizes the consent copy. The consent step itself always renders and cannot be turned off.
className, styleApplied to the root element.
children(auth: UseLoginWithChatGPTResult) => ReactNodeFull custom renderer. Replaces all default UI, including consent. Render equivalent consent before calling login().

What it renders

StateUI
loadingSpinner with "Checking session…".
unauthenticatedThe login button. Clicking opens the consent popup; if popups are blocked, the same consent renders inline.
connectingDisabled button with spinner.
pendingThe user code with a copy button, verification link, and hint.
authenticatedConnected chip with avatar, plan, and a Disconnect button.
expired / errorRetryable error state; error text renders below the UI.

The widget injects one <style id="lwc-styles"> element with .lwc-* classes on first mount. Override those classes to restyle without a custom renderer.

useLoginWithChatGPT()

"use client";

import { useLoginWithChatGPT } from "@opencoredev/loginwithchatgpt-react";

const auth = useLoginWithChatGPT({ pollIntervalMs: 2500 });

See Custom sign-in UI for a complete example.

Options

OptionTypeDefaultNotes
basePathstring"/api/chatgpt"Must match the handler's basePath.
fetchtypeof fetchglobal fetchFor credentialed or cross-origin requests.
pollIntervalMsnumber2500Client cadence while pending. The server still respects the upstream interval, so lower values only tighten UI latency.
openPopupbooleantrueOpen the verification URL after starting login.
autoCopyCodebooleantrueCopy the user code before opening the popup (clipboard writes fail after focus loss).
onAuthenticated(user?: ChatGPTUser) => voidFires when status becomes authenticated.
onError(error: Error) => voidFires when login startup fails.

Returned value

interface UseLoginWithChatGPTResult {
  status: "loading" | "unauthenticated" | "connecting" | "pending"
        | "authenticated" | "expired" | "error";
  user?: ChatGPTUser;          // when authenticated
  userCode?: string;           // when pending
  verificationUrl?: string;    // when pending
  copied: boolean;             // true briefly after a clipboard write
  error?: string;

  login(options?: { popup?: Window | null }): Promise<void>;
  logout(): Promise<void>;
  copyCode(): Promise<void>;
  reopen(): void;              // refocus or reopen the verification popup

  isAuthenticated: boolean;
  isPending: boolean;
  isConnecting: boolean;
}

Behavior notes:

  • On mount the hook checks GET /session once. Until it answers, status is "loading".
  • login({ popup }) navigates a pre-opened window instead of opening a new one. That is how the consent popup hands itself over.
  • logout() clears local state even if the network call fails.
  • All requests use credentials: "same-origin" unless you pass a fetch wrapper.

openLoginWithChatGPTConsentPopup()

Opens the built-in consent popup and, on continue, calls your login with that popup so the verification page loads in the same window:

import { openLoginWithChatGPTConsentPopup } from "@opencoredev/loginwithchatgpt-react";

const popup = openLoginWithChatGPTConsentPopup({
  appName: "Acme",
  continueLabel: "I trust this app, continue",
  securityHref: "https://acme.dev/security",
  login: auth.login,
});
// null when the popup was blocked — fall back to inline consent.

Icons

ChatGPTMark and Spinner are exported as plain SVG components (fill="currentColor", aria-hidden). OpenAIMark is a deprecated alias of ChatGPTMark kept for older imports.

For a full custom-UI walkthrough with consent patterns, see Custom sign-in UI.

On this page