关于 login-with-chatgpt
login-with-chatgpt 是用于在 Web 应用中接入 ChatGPT 账户登录及服务端 Responses 调用的 SDK,包含服务端、React 和 AI SDK 包,并默认将令牌留在服务端。
主要功能
- 01ChatGPT 设备流登录
- 02基于 Cookie 的会话管理
- 03流式 Responses 代理
- 04按账户发现可用模型
- 05React 登录组件与 Hook
- 06AI SDK 文本、工具和图像支持
适用场景
- 01为 Web 应用添加 ChatGPT 登录
- 02通过服务端路由流式传输模型响应
- 03选择登录账户可用的模型
- 04使用 AI SDK 生成或编辑图像
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ opencoredev/ login-with-chatgpt --skill login-with-chatgpt安装后在 Claude Code 中输入/login-with-chatgpt确认已加载。
详细介绍
使用 ChatGPT 登录
用于“使用 ChatGPT 账户登录”的 SDK。用户通过 OpenAI 的设备流程进行身份验证;处理程序保留令牌,并将 Responses 风格的调用代理到由 ChatGPT 提供支持的 Codex 端点。 浏览器中始终只保存 HttpOnly 会话 Cookie。
规则:编写代码前请阅读
- 没有 API 密钥。 身份验证来自每位用户的 ChatGPT 会话。
切勿添加
OPENAI_API_KEY,也切勿在此流程中直接调用api.openai.com。请求应通过应用自身的/api/chatgpt/responses代理,或 基于auth.proxyFetch(request)构建的服务端路由发送。 - 选择模型前先查询。 模型可用性因账户和套餐而异。调用
await chatgpt.listModels()(浏览器端)或await auth.getModels(request)(服务端),然后从结果中选择。 可以使用硬编码的allowedModels作为限制,但不能假设每个已登录账户都能使用同一个模型。 - 默认情况下,令牌仅保留在处理程序内部。 不要构建向客户端返回令牌的端点。常规应用代码应使用
/responses、/models或auth.proxyFetch(request)。导出原始令牌必须显式启用dangerouslyAllowTokenExport这一逃逸开关。 - 不能省略用户同意步骤。 组件始终会在 OpenAI 验证页面之前显示同意步骤。自定义 UI 必须在调用
login()之前 呈现等效的同意步骤。 - 生产环境需要稳定的
secret和共享的sessionStore。 默认值(临时密钥、内存存储)会导致每次重启后所有用户都退出登录, 并且在无服务器实例之间无法正常工作。
软件包
| 软件包 | 用途 |
|---|---|
@opencoredev/loginwithchatgpt-server | 用于登录、会话、登出、模型和流式代理的 createChatGPTHandler() |
@opencoredev/loginwithchatgpt-react | <LoginWithChatGPT /> 按钮、useLoginWithChatGPT() Hook |
@opencoredev/loginwithchatgpt-ai | Vercel AI SDK 提供程序(ai 和 @ai-sdk/openai 是 peer 依赖) |
@opencoredev/loginwithchatgpt-core | 底层 OAuth/设备流程、错误和类型;很少直接导入 |
bun add @opencoredev/loginwithchatgpt-server @opencoredev/loginwithchatgpt-react @opencoredev/loginwithchatgpt-ai ai @ai-sdk/openai
服务端处理程序
一个处理程序负责处理 basePath(默认为 /api/chatgpt)下的所有内容。它基于 Web 标准的 Request、Response、fetch 和
crypto.subtle 编写,因此应在提供这些 API 的运行时中使用。
// Next.js: app/api/chatgpt/[...lwc]/route.ts
import { createChatGPTHandler } from "@opencoredev/loginwithchatgpt-server";
const auth = createChatGPTHandler({
secret: process.env.LWC_SECRET, // openssl rand -hex 32
responsesProxy: {
allowedModels: ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"],
},
});
export const GET = (request: Request) => auth.handler(request);
export const POST = (request: Request) => auth.handler(request);
// Bun
Bun.serve({
routes: {
"/": index,
"/api/chatgpt/*": (req) => auth.handler(req),
},
});
主要选项:basePath、secret、sessionStore(任何
get/set/delete 键值存储)、cookieName、cookie、
sessionTtlMs(30 天)、defaultModel("gpt-5.5")、
enableResponsesProxy(设为 false 时也会禁用 /models)、responsesProxy
(allowedModels、maxRequestBytes 40 MiB、rateLimit 默认
30 次/分钟/会话)、allowedOrigins(跨源 CSRF 允许列表)。
返回的处理程序提供的服务端辅助方法(均会读取会话 Cookie):
auth.getSession(request)→{ status, user? };不会调用上游服务。auth.proxyFetch(request)→ 用于自定义服务端 AI 路由的请求级 fetch,不会暴露原始 bearer 令牌。auth.getModels(request)→ 账户的模型标识符,或undefined。auth.dangerouslyGetTokens(request)→ 原始令牌逃逸开关;需要启用dangerouslyAllowTokenExport。
React 登录
"use client";
import { LoginWithChatGPT } from "@opencoredev/loginwithchatgpt-react";
<LoginWithChatGPT
consent={{ appName: "Acme" }}
onAuthenticated={(user) => console.log("connected", user?.email)}
/>;
此组件会处理完整流程:同意弹窗 → OpenAI 验证 →
复制代码 → 轮询 → 显示带有断开连接选项的已登录状态标记。可通过注入的 .lwc-* 类重新设置样式,或传入 children 渲染函数以实现完全自定义的 UI(此时需自行呈现同意步骤,并使用
openLoginWithChatGPTConsentPopup())。
对于自定义 UI,useLoginWithChatGPT({ basePath?, pollIntervalMs?, ... })
会返回 { status, user, userCode, verificationUrl, login, logout, copyCode, reopen, isAuthenticated, isPending }。status 的值可以是
loading | unauthenticated | connecting | pending | authenticated | expired | error。
使用 AI SDK 进行流式传输
浏览器代理提供方,从 cookie 在服务端注入凭据:
import { createChatGPTProxyProvider } from "@opencoredev/loginwithchatgpt-ai";
import { streamText } from "ai";
const chatgpt = createChatGPTProxyProvider(); // { basePath } if not /api/chatgpt
const models = await chatgpt.listModels(); // throws ChatGPTProxyError; status 401 = signed out
const model = models.includes("gpt-5.5") ? "gpt-5.5" : models[0];
const result = streamText({ model: chatgpt(model), prompt });
用于自有 AI 路由的服务端代理提供方:
import { createChatGPTProxyProvider } from "@opencoredev/loginwithchatgpt-ai";
import { streamText } from "ai";
export async function POST(request: Request) {
const chatgpt = createChatGPTProxyProvider({
fetch: auth.proxyFetch(request),
});
const { prompt } = await request.json();
return streamText({ model: chatgpt(), prompt }).toUIMessageStreamResponse();
}
模型支持 streamText、generateText、工具调用、结构化输出,以及通过标准 AI SDK messages 附加文件。图像是提供方 API 的一等功能:使用 chatgpt.images.generate() 通过提示词生成图像,使用 chatgpt.images.edit() 编辑图像;支持多个参考图、蒙版、输入保真度、自定义尺寸、质量、格式、压缩、背景、多个输出和部分图像回调。两者都通过 /responses 使用已登录用户的 ChatGPT 套餐;无需添加 API 密钥。不提供嵌入和音频功能。
POST /responses 请求级调优请求头:
x-login-with-chatgpt-reasoning-effort(none|low|medium|high|xhigh)和
x-login-with-chatgpt-service-tier(auto|default|flex|priority|fast)。
HTTP 路由(相对于 basePath)
| 路由 | 用途 |
|---|---|
POST /login | 启动设备登录 → { status: "pending", userCode, verificationUrl, interval, expiresAt } |
GET /status | 通过一次轮询推进登录流程,并返回状态 |
GET /session | 读取状态(开销低),不会轮询上游 |
POST /logout | 删除会话并清除 cookie |
GET /models | 账户的模型 slug(未登录时返回 401) |
POST /responses | 流式 Responses 风格代理 |
非 GET 路由会基于 Origin 执行 CSRF 防护:仅允许同源请求或 allowedOrigins 中的来源。前后端分离部署还需要 SameSite=None cookie、携带凭据的 fetch 请求和 CORS 请求头(参见跨域指南)。
生产环境检查清单
- 设置
LWC_SECRET(在各次部署间保持稳定;轮换后会让所有用户退出登录)。 - 使用共享的
sessionStore(Redis/DB)。MemoryStore仅用于开发环境。 - 设置
responsesProxy.allowedModels;运行多个实例时,传入共享的rateLimit.store。 - 使用 HTTPS,并转发
X-Forwarded-Proto,以便为 cookie 设置Secure。 - 记录
/responses元数据(会话 ID、模型、状态、耗时),绝不记录提示词或附件。
错误
ChatGPTAuthError(来自 core)包含 .code、.status、.body。值得注意的代码:refresh_token_invalid(会话已失效;处理程序会删除会话并报告 expired;可使用 isRefreshTokenInvalid(error) 检测)、not_authenticated、token_refresh_failed(可重试)、models_request_failed。浏览器提供方的 listModels() 会抛出带有 .status 的 ChatGPTProxyError。来自 /responses 的 HTTP 错误:401 not_authenticated、403 model_not_allowed / origin_not_allowed、413 responses_request_too_large、429 rate_limited(附带 retry-after)。
文档
完整文档位于仓库的 docs/content/docs/ 下(quickstart、concepts/security、guides/production、reference/*)。文档站点还提供 /llms.txt 和各页面的 Markdown 文件,路径为 /llms.mdx/docs/<path>/content.md。