15 Commits

Author SHA1 Message Date
kshitijk4poor
1086bd6ccc fix(auth): bound device-poll edge backoff and gate 403 on x-vercel-mitigated
The edge/WAF backoff in the shared Nous+xAI device-code poll loop had three
gaps found in review:

- Retry-After was parsed with a bare int() and never capped, so a
  `Retry-After: 3600` slept an hour past a 5-15 minute device code. Parse it
  with the shared agent.retry_utils.parse_retry_after_seconds and bound every
  sleep by min(60, time left before the device-code deadline).
- The backoff was written into current_interval, so after a block normal
  authorization_pending polls kept the inflated interval and slow_down grew
  from it. Keep it in its own edge_backoff, reset on any OAuth JSON response.
- Any non-JSON 403 was treated as transient, disagreeing with the refresh
  classifier from the previous commit. Only a 403 carrying
  x-vercel-mitigated is the edge speaking; a header-less non-JSON 403 raises
  as before. 408/429/5xx stay transient.

Tests reduced to the two invariants: recovery after edge blocks (each sleep
<= 60, back to the server interval afterwards) and a persistent block ends at
the deadline without oversleeping.
2026-09-24 18:06:48 +05:30
zzragida
0b5eeab93a fix(auth): keep device-code polling alive through edge/WAF non-JSON errors
The generic RFC 8628 device-token poll loop (shared by the Nous Portal and
xAI flows) aborted the whole login when the token endpoint returned a
non-JSON error body. Vercel fronts the Nous Portal and answers rate-limited
clients with a text/plain 403 (x-vercel-mitigated: deny) or 429 — no JSON
body, so such a response can never carry authorization_pending/slow_down.
One mitigation response mid-approval killed a device login the user may
still be approving in the browser.

Treat non-JSON 403/408/429/5xx as transient: back off (doubling from the
current interval, floor 5s, cap 60s; Retry-After honored when present) and
keep polling until the device code expires. Statuses outside that set keep
the existing abort behavior and JSON OAuth errors keep each caller's exact
error contract.

Co-Authored-By: Claude Code <noreply@anthropic.com>
(cherry picked from commit 13ff660c5ebcbade203faad5e63c12de0603af5f)
2026-09-24 18:06:48 +05:30
teknium1
23036e20a6 fix(ux): plain-language, actionable user-facing messages (core)
Squashed integration of the user-facing message audit for this surface set.
Full per-finding receipts: /tmp/ux-audit/lanes/*-receipt.md (campaign artifacts).
2026-09-15 04:12:13 -07:00
Teknium
3310298a37 refactor(auth): share the loopback PKCE listener between OAuth flows
Move the S256 verifier/challenge pair, the loopback callback handler, the bind-first
listener and the serve-until-redirect loop out of auth_spotify into auth_device_flow so a
second loopback PKCE provider does not copy 80 lines of HTTP-server plumbing. Spotify's
behaviour and error codes are unchanged; only its private copies are deleted.
2026-09-12 22:07:41 -07:00
Siddharth Balyan
cbcf7b72f7 feat(gateway): sign in with a Nous account from a chat (/login), one shared sign-in flow (#105261)
* refactor(auth): one sign-in flow behind SignInState, rendered by the CLI and the desktop

* feat(gateway): /signin signs the free tier into a Nous account from a DM

* feat(cli): chat surfaces name /signin as the sign-in verb

* fix(auth): review follow-ups for the shared sign-in flow and /signin

* fix(i18n): carry the /status free-tier line in every locale catalog

* refactor(cli): the chat sign-in command is /login

* fix(auth): durable override cleanup in the /login sweep, and the sign-in flow in its own modules
2026-09-11 03:45:33 +05:30
Teknium
e83816a4d1 review-fix(comments): restore lost #NNNN rationale comments across non-test source (mechanical sweep, condensed, code unchanged)
For each issue anchor present in BASE 63279301bc non-test .py and absent on HEAD, the BASE comment/docstring block was re-attached at the HEAD location of the code it explained (matched by the distinctive code line / enclosing def). Sentences already covered by an existing HEAD comment were deduped; the issue number always survives. Insert-only: no code lines changed.
2026-09-03 09:44:26 -07:00
Teknium
0a142eff58 refactor(hermes_cli): auth_oauth_grants/device_flow — fold guard pairs, single browser-open try path, list-comp log bits 2026-09-02 23:18:23 -07:00
Teknium
55a4b75347 refactor(hermes_cli): auth group B — squeeze body blanks, fold repeated AuthError ctor 2026-09-02 22:27:46 -07:00
Teknium
31e6c6fab4 refactor(hermes_cli): auth_nous/codex — unify refresh_nous_oauth_pure into from_state, codex login POST helper 2026-09-02 22:18:03 -07:00
Teknium
1ecf5e96f9 refactor(hermes_cli): auth group B — final closer hug pass 2026-09-02 21:55:47 -07:00
Teknium
856fd5613c refactor(hermes_cli): auth group B — pack signatures, move heal notice into _HealPass 2026-09-02 21:35:49 -07:00
Teknium
34a6f963f8 refactor(hermes_cli): auth_nous/codex/device_flow/oauth_grants — AST-neutral layout compaction 2026-09-02 21:02:27 -07:00
Teknium
40a09152f1 refactor(hermes_cli): compact auth_device_flow + split forked-OAuth heal into _HealPass phases 2026-09-02 20:09:37 -07:00
Teknium
c990225fa0 refactor(auth): relocate single-consumer helpers next to their users; _decode_jwt_claims to constants leaf 2026-09-02 16:09:47 -07:00
Teknium
d32014a4a6 refactor(auth): split OAuth-grant hygiene, device-flow helpers, model picker and Kimi/Z.AI detection into modules 2026-09-02 15:48:08 -07:00