Login with ChatGPT

Quickstart

Install the SDK, mount the server handler, render the sign-in button, and stream a response.

This page wires the default path: a server route at /api/chatgpt/*, a React sign-in button, and a browser-safe AI SDK provider that streams through your backend.

Install the packages

bun add @opencoredev/loginwithchatgpt-server @opencoredev/loginwithchatgpt-react @opencoredev/loginwithchatgpt-ai ai @ai-sdk/openai

ai and @ai-sdk/openai are peer dependencies of @opencoredev/loginwithchatgpt-ai.

Set a secret

The secret signs the session cookie and encrypts tokens before they enter your session store. Without one, the SDK generates an ephemeral secret and logs a warning, and every restart logs everyone out.

.env
LWC_SECRET="use-the-output-of: openssl rand -hex 32"

Mount the server handler

createChatGPTHandler() returns one Web-standard handler that owns login, polling, logout, model listing, and the streaming proxy.

index.ts
import { createChatGPTHandler } from "@opencoredev/loginwithchatgpt-server";
import index from "./index.html";

const auth = createChatGPTHandler({
  secret: process.env.LWC_SECRET,
  responsesProxy: {
    allowedModels: ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"],
  },
});

Bun.serve({
  routes: {
    "/": index,
    "/api/chatgpt/*": (req) => auth.handler(req),
  },
});

The handler only needs Web-standard Request, Response, fetch, and crypto, so any runtime with those works.

Render the sign-in button

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

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

export function SignIn() {
  return (
    <LoginWithChatGPT
      consent={{ appName: "Acme" }}
      onAuthenticated={() => console.log("ChatGPT session connected")}
    />
  );
}

Clicking the button opens a consent popup first. It cannot be disabled, only customized. If the user continues, the same popup goes to OpenAI's verification page, the widget copies the user code, polls for completion, and renders the signed-in state:

The sign-in flow: consent, then the device code and verification window

Discover models and stream

Model availability depends on the account and plan, so ask instead of hardcoding a list. The proxy provider sends everything to your handler, which injects credentials from the session cookie.

lib/chat.ts
import { createChatGPTProxyProvider } from "@opencoredev/loginwithchatgpt-ai";
import { streamText } from "ai";

const chatgpt = createChatGPTProxyProvider();

export async function ask(prompt: string) {
  const models = await chatgpt.listModels(); // GET /api/chatgpt/models
  const model = models.includes("gpt-5.5") ? "gpt-5.5" : models[0];
  if (!model) throw new Error("No ChatGPT models returned for this account.");

  return streamText({ model: chatgpt(model), prompt });
}
const result = await ask("Explain HTTP cookies in one paragraph.");

for await (const delta of result.textStream) {
  process.stdout.write(delta);
}

Verify

  1. Click the button, continue past consent, and authorize in the OpenAI window.
  2. GET /api/chatgpt/session returns { "status": "authenticated" }.
  3. GET /api/chatgpt/models returns at least one model slug.
  4. A prompt streams text back through POST /api/chatgpt/responses.

Next

On this page