DurinDoor
Providers

ChatGPT Web

Connect a ChatGPT web session, choose browser or HTTP transport, and diagnose session or browser failures.

ChatGPT Web (chatgpt-web, alias cgpt-web) sends chat requests through your logged-in chatgpt.com session. You paste the session cookie once; DurinDoor keeps it and writes back the rotated cookie when chatgpt.com issues a new one.

This drives the consumer ChatGPT web app, not the OpenAI API. It depends on chatgpt.com's private web endpoints, which change without notice, and on your account's own limits. Use it for a personal gateway.

Models

IdChatGPT UI choice
gpt-5-6GPT-5.6 Sol, Instant
gpt-5-6-thinkingGPT-5.6 Sol, Thinking; reasoning_effort picks the level (alias gpt-5-6-sol)
gpt-5-6-proGPT-5.6 Sol, Pro
gpt-5.6-luna-freeGPT-5.6 Luna on a Free account
gpt-5.6-luna-free-thinkingGPT-5.6 Luna with Think on
gpt-5-5-instantGPT-5.5, Instant
gpt-5-5-thinkingGPT-5.5, Thinking; reasoning_effort picks the level (alias gpt-5-5)
gpt-5-5-proGPT-5.5, Pro

Your plan decides which of these chatgpt.com accepts. This checkout exposes two Luna aliases for Free sessions. chatgpt.com decides which models your account currently accepts.

chatgpt.com keeps its NextAuth session in __Secure-next-auth.session-token. When the session is larger than about 4KB, NextAuth splits it into chunks named __Secure-next-auth.session-token.0, .1, and so on, each holding a different part of the value. DurinDoor accepts any of these pastes:

  • a bare token value
  • name=value for the plain cookie or a chunk
  • the full Cookie header, with or without the Cookie: prefix, chunks in any order

Chunks are sent back to chatgpt.com under their own names, ordered by index, never concatenated. If a header has both chunks and a plain cookie, the stale plain one is dropped. Other cookies in the paste, such as cf_clearance, are kept. The Check button calls https://chatgpt.com/api/auth/session with that cookie; a live session returns an accessToken, and an expired or incomplete one returns {}.

The session cookies are HttpOnly. No script on the page can read them: document.cookie and cookieStore.getAll() both leave them out. Two ways work:

  1. DevTools, Network, reload chatgpt.com, select any request to chatgpt.com, and copy the whole Cookie request header value. Paste it as is.
  2. DevTools, Application, Cookies, https://chatgpt.com. Run this in the Console and paste each chunk's Value when asked. The joined name=value string lands on your clipboard (copy() is a DevTools console helper). Review any browser paste warning, or copy the header from Network instead.
(()=>{const p=[];for(let i=0;;i++){const v=prompt(`Value of __Secure-next-auth.session-token.${i} (Cancel when done)`);if(!v)break;p.push(`__Secure-next-auth.session-token.${i}=${v.trim()}`)}copy(p.join("; "))})()

The add-connection dialog shows the same steps and a copy button for the snippet.

A same-origin fetch("/api/auth/session") in the chatgpt.com console does return the short-lived accessToken. That token is for the Codex provider (its Bulk import JSON takes accessToken, as does POST /api/oauth/codex/import-token), not for ChatGPT Web, and it has no refresh token:

copy((await (await fetch("/api/auth/session")).json()).accessToken)

Transports

DurinDoor has two ways to talk to chatgpt.com. The connection's providerSpecificData.transport picks one:

ValueBehavior
auto (default)Browser. HTTP when the request carries tools, or when the browser cannot start (no playwright package, no Chromium, no display, DURINDOOR_BROWSER_POOL=off).
browserBrowser only. A missing browser is an error (HTTP 503).
httpHTTP only.

Browser (primary)

DurinDoor opens chatgpt.com in a pooled Playwright Chromium, loads your cookie into it, and sends the turn through the page's own code. The page handles browser authentication and challenge flows. Browser contexts are pooled per connection and closed after idle time. Challenges can still reject a session.

  • Tools are not supported on this path; auto sends tool requests to HTTP.
  • Image and file inputs are uploaded through the page (up to 10 attachments, 20 MB per image, 50 MB per file and in total). Remote image URLs are fetched with private and metadata addresses blocked.
  • The browser runs headed, off-screen, because chatgpt.com rejects some headless sessions. Headless is available with DURINDOOR_CHATGPT_WEB_HEADLESS=1 or the connection's headless: true; it may be refused.
  • A connection proxy is applied to the browser context.

HTTP (fallback)

The HTTP transport calls chatgpt.com's backend directly over tls-client-node, which presents a Firefox TLS fingerprint. Per request it exchanges the cookie for an access token at /api/auth/session (cached for 5 minutes), warms the session, asks Sentinel for chat requirements, solves the SHA3-512 proof-of-work in Node, and posts the conversation. It supports tool calls through prompt emulation, GPT-5.6 Sol Pro handoff resumes, and generated images, which it caches for 30 minutes and serves from /v1/chatgpt-web/image/<id>.

This path cannot solve Turnstile. When Sentinel asks for it, DurinDoor still sends the turn (chatgpt.com sometimes accepts it) and passes a connection's turnstileToken if one is set. When Sentinel refuses outright, the request fails with SENTINEL_BLOCKED. Browser mode can handle challenges through the page, but success still depends on the account and site accepting that browser session.

tls-client-node downloads its native library into $DATA_DIR/tls-client/bin on first use. The library is built for glibc; on Alpine it needs gcompat, which the Docker image installs.

Chromium requirement

The browser transport needs Chromium or Chrome on the DurinDoor host. DurinDoor looks for a browser in this order:

  1. The connection's chromeExecutablePath.
  2. CHATGPT_WEB_CHROME_PATH, then CHROME_PATH.
  3. Standard Google Chrome and Chromium install paths on macOS, Linux and Windows.
  4. Playwright's own Chromium.

To install Playwright's Chromium:

npx playwright install chromium

Set DURINDOOR_BROWSER_AUTO_INSTALL=1 to have DurinDoor run that install on first use instead. If no browser is found and auto-install is off, auto falls back to HTTP and browser answers 503 with the command to run.

On a Linux server without a display, run DurinDoor under Xvfb (xvfb-run -a npm run start) or switch to headless as above.

Docker

The image installs Alpine's chromium, xvfb and gcompat, sets CHATGPT_WEB_CHROME_PATH=/usr/bin/chromium-browser, and starts Xvfb on :99 when DISPLAY is unset. DURINDOOR_XVFB=0 skips Xvfb. Build with --build-arg CHATGPT_WEB_BROWSER=false for a smaller image without the browser; ChatGPT Web then uses HTTP.

Environment

VariableDefaultEffect
DURINDOOR_BROWSER_POOLonoff disables the browser pool.
DURINDOOR_BROWSER_AUTO_INSTALLoff1 installs Playwright's Chromium on first use.
DURINDOOR_CHATGPT_WEB_HEADLESSoff1 runs the browser headless.
CHATGPT_WEB_CHROME_PATHunsetChrome or Chromium binary for the browser transport.
DURINDOOR_CHATGPT_TLS_TIMEOUT_MS60000HTTP transport request timeout.
DURINDOOR_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS30000HTTP transport wait for the first streamed byte.
DURINDOOR_CGPT_WEB_PRO_TIMEOUT_MS1200000How long HTTP waits on a Pro answer.
DURINDOOR_CGPT_WEB_IMAGE_CACHE_MAX_MB10Image cache size for the HTTP transport.
DURINDOOR_PUBLIC_BASE_URLunsetPublic URL used in generated image links.

Connection settings

These optional providerSpecificData fields apply to a ChatGPT Web connection:

FieldUse
transportauto, browser or http.
storageStateA Playwright storage-state JSON (cookies and local storage) to use instead of the pasted cookie. Rotated cookies are not written back for this form.
chromeExecutablePathBrowser binary for this connection.
headlesstrue or false, overriding DURINDOOR_CHATGPT_WEB_HEADLESS.
customUserAgent, locale, timezoneBrowser context settings.
turnstileTokenA Turnstile token for the HTTP transport.

Connect and verify

  1. Sign in to chatgpt.com and copy the complete session Cookie header using the method above.
  2. Open Providers → ChatGPT Web, paste the cookie, and save. Keep every .0, .1, and later chunk.
  3. Install a browser if you selected browser mode. On a server, provide a display or choose the documented headless or HTTP mode.
  4. Send a short request using a ChatGPT Web model your plan supports.
  5. Confirm the request on Usage. Test attachments and tools separately.

If session validation returns an empty object, copy a fresh complete cookie. For 503 in browser mode, check Chromium and the display. For SENTINEL_BLOCKED, try a supported browser session rather than assuming HTTP can solve Turnstile. Tool calls use prompt emulation over HTTP and may differ from native API tools. Private web endpoints and account restrictions can change without a DurinDoor release.

On this page

Edit on GitHub