Skip to content

add ChatGPT device-code login flow#93

Merged
ndycode merged 4 commits intomainfrom
feat/device-code-auth
Mar 22, 2026
Merged

add ChatGPT device-code login flow#93
ndycode merged 4 commits intomainfrom
feat/device-code-auth

Conversation

@ndycode
Copy link
Copy Markdown
Owner

@ndycode ndycode commented Mar 22, 2026

Summary

  • Added a ChatGPT Plus/Pro MULTI (Device Code) login path, extracted shared account-selection and persistence helpers, and updated the browser/manual fallback messaging around localhost callback failures.
  • This gives SSH, WSL, and headless users a first-party login option when the local callback flow is inconvenient or unavailable, while keeping account persistence behavior consistent across login flows.

Testing

  • npm run lint
  • npm run build
  • npm test
  • Not applicable

Compliance Confirmation

  • This change stays within the repository scope and OpenAI Terms of Service expectations.
  • This change uses official authentication flows only and does not add bypass, scraping, or credential-sharing behavior.
  • I updated tests and documentation when the change affected users, maintainers, or repository behavior.

Notes

  • Linked issue: N/A
  • Safety notes: auth-server error logs now redact response bodies to a short prefix, and persistAccountPool stays behind withAccountStorageTransaction with overlapping-write coverage in test/login-runner.test.ts.
  • Follow-up work or rollout notes: Device code currently follows the single-account/manual login path; broader auth parity work can build on the extracted shared runner.

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this PR adds a device-code login path (lib/auth/device-code.ts) for ssh, wsl, and headless users and extracts the shared resolveAccountSelection + persistAccountPool helpers into lib/auth/login-runner.ts, deduplicating the three previously-inline copies in index.ts. the new auth method sits between the browser-oauth and manual-url-paste entries in the methods list.

key things done well

  • getRedactedErrorBody truncates error bodies to 120 chars before logging — addresses the prior review concern on both the usercode and poll paths, with dedicated test coverage in test/device-code.test.ts
  • persistAccountPool is documented with a JSDoc block explaining why withAccountStorageTransaction serialises concurrent writes and handles the windows lock-retry path
  • test/login-runner.test.ts includes a concrete concurrency regression test that blocks the first fs.rename and verifies both accounts survive a simultaneous login — directly exercises the windows-safety claim
  • parseIntervalSeconds enforces a floor of 1 second, preventing a busy-loop on a server returning 0

remaining p2 items

  • the device-code authorize callback always passes false as replaceAll to persistAuthenticatedSelections, so a "start fresh" login via device code silently keeps existing accounts rather than replacing them — this is consistent with the manual-url-paste flow and noted in the PR, but a short inline comment would prevent confusion for future maintainers
  • the timeout message in completeDeviceCodeSession hardcodes "15 minutes" regardless of the maxWaitMs option — fine for production use, minor inaccuracy in tests

Confidence Score: 4/5

  • safe to merge with the documented startFresh gap acknowledged — no production bugs, no data loss risk
  • prior concerns (log redaction, concurrency documentation, regression test) are all addressed. the two remaining p2s are non-blocking style items. the extracted login-runner.ts is a faithful lift with no logic changes. test coverage covers the new paths including concurrent persist and body-truncation.
  • index.ts — device-code callback's startFresh: false hardcoding is the only item that deserves a follow-up if "start fresh via device code" behaviour is ever needed

Important Files Changed

Filename Overview
lib/auth/device-code.ts new device-code flow: session creation + polling + exchange. redaction via truncation (120-char limit) is in place and tested. timeout message hardcodes "15 minutes".
lib/auth/login-runner.ts extraction of resolveAccountSelection + persistAccountPool from index.ts. JSDoc documents withAccountStorageTransaction concurrency guarantee. code is a faithful lift with no logic changes.
index.ts new device-code auth method added; persistAuthenticatedSelections extracted. startFresh not forwarded to device-code persist (always false). error messages now mention Device Code as fallback.
test/login-runner.test.ts new concurrent-persist regression test blocks the first rename until the second persist starts, then verifies both accounts survive. directly addresses the windows filesystem concurrency concern.
test/device-code.test.ts covers session creation, 404 unavailability, log-body redaction (both paths), polling + exchange, and timeout. solid unit coverage for the new module.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant P as Plugin (index.ts)
    participant DC as device-code.ts
    participant AS as Auth Server
    participant LR as login-runner.ts
    participant S as Storage (withAccountStorageTransaction)

    U->>P: select "Device Code" auth method
    P->>DC: createDeviceCodeSession()
    DC->>AS: POST /api/accounts/deviceauth/usercode
    AS-->>DC: { device_auth_id, user_code, interval }
    DC-->>P: DeviceCodeReadyResult { session }
    P-->>U: show verificationUrl + userCode instructions

    U->>AS: open verificationUrl, enter userCode

    P->>DC: completeDeviceCodeSession(session)
    loop poll every intervalSeconds (403/404 = pending)
        DC->>AS: POST /api/accounts/deviceauth/token
        AS-->>DC: 403 (pending) or { authorization_code, code_verifier }
    end
    DC->>AS: exchangeAuthorizationCode(authCode, codeVerifier, redirectUri)
    AS-->>DC: TokenResult (access + refresh tokens)
    DC-->>P: TokenResult success

    P->>LR: resolveAccountSelection(tokens)
    LR-->>P: AccountSelectionResult { primary, variantsForPersistence }
    P->>LR: persistAccountPool(variants, replaceAll=false)
    LR->>S: withAccountStorageTransaction (serialized write)
    S-->>LR: persisted
    P-->>U: login complete
Loading

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: index.ts
Line: 1063-1066

Comment:
**`startFresh` not forwarded to device-code persist**

the device-code callback always passes `false` as `replaceAll`, so if a user opens the "start fresh" login path and selects device code, their existing accounts are silently preserved instead of being cleared. the browser-oauth flow honours `startFresh` properly with `isFirstAccount && startFresh`.

this is acknowledged in the PR description as a known limitation, but it's worth noting here because it's a silent divergence in behaviour from the browser flow. the `startFresh` variable is in scope in the enclosing closure if you ever want to close the gap:

```typescript
// current
await persistAuthenticatedSelections(
    selection.variantsForPersistence,
    false,
);

// to match browser-oauth behaviour:
await persistAuthenticatedSelections(
    selection.variantsForPersistence,
    startFresh,
);
```

if the intent is to keep device-code as "add only" for now, a short inline comment here would prevent a future maintainer from wondering why `startFresh` isn't used.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/auth/device-code.ts
Line: 287-291

Comment:
**timeout message hardcodes "15 minutes" regardless of `maxWaitMs`**

the timeout error message is static even though `completeDeviceCodeSession` accepts a `maxWaitMs` override. this is only observable today via the test (`maxWaitMs: 0`), but if callers ever vary the timeout the message will mislead users.

```suggestion
		message: `Device code authorization timed out after ${Math.round(maxWaitMs / 60_000)} minutes`,
```

for the default case this still emits "15 minutes", and for the test case with `maxWaitMs: 0` it would emit "0 minutes" — you'd need to update the `toEqual` assertion in `test/device-code.test.ts` accordingly (or use `toContain("timed out")`).

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix(auth): redact device-code logs" | Re-trigger Greptile

Context used:

  • Rule used - What: Every code change must explain how it defend... (source)

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

Warning

Rate limit exceeded

@ndycode has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 51 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5a839bb0-fa76-47e1-b301-f1460e6e2510

📥 Commits

Reviewing files that changed from the base of the PR and between eaf9641 and ee79105.

📒 Files selected for processing (11)
  • docs/getting-started.md
  • docs/troubleshooting.md
  • index.ts
  • lib/auth/device-code.ts
  • lib/auth/login-runner.ts
  • lib/auth/server.ts
  • lib/constants.ts
  • lib/index.ts
  • test/device-code.test.ts
  • test/index.test.ts
  • test/login-runner.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/device-code-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread lib/auth/device-code.ts Outdated
Comment thread lib/auth/device-code.ts
@ndycode ndycode merged commit a53e365 into main Mar 22, 2026
2 checks passed
@ndycode ndycode deleted the feat/device-code-auth branch March 22, 2026 14:05
ndycode added a commit that referenced this pull request Apr 6, 2026
add ChatGPT device-code login flow
ndycode added a commit that referenced this pull request Apr 6, 2026
add ChatGPT device-code login flow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant