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/openaiai 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.
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.
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
"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:

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.
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
- Click the button, continue past consent, and authorize in the OpenAI window.
GET /api/chatgpt/sessionreturns{ "status": "authenticated" }.GET /api/chatgpt/modelsreturns at least one model slug.- A prompt streams text back through
POST /api/chatgpt/responses.