Skip to content

feat(providers): derive + surface expiry for JWT-bearing web cookies (#11497) - #11505

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
oyi77:feat/webcookie-expiry-preview
Aug 25, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
oyi77:feat/webcookie-expiry-preview

Conversation

@oyi77

@oyi77 oyi77 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Closes #11497.

What

Web-cookie rows had no expiry signal even when the pasted credential embeds a standard JWT with an exp claim (ChatGPT __Secure-next-auth.session-token, Qwen/Z.ai localStorage tokens). Operators got their first indication of expiry from a live request failing.

  • New pure util src/shared/utils/webCookieExpiry.ts:
    • decodeJwtPayloadExp — strict JWT-shaped decode (3 dot segments, base64url, JSON-object payload, positive numeric exp), size-capped;
    • deriveCookieExpiryIso — scans the whole credential then each cookie-pair value;
    • withDerivedCookieExpiry — merge helper that RECOMPUTES on every save: re-pasting refreshes the date, an opaque replacement cookie drops the stale date instead of leaving a lie on the row.
  • Persistence at the existing chokepoint: normalizeConnectionProviderSpecificData in src/lib/db/providers.ts (same place the Codex fingerprint seed is applied) — covers create/edit/import/health-stamp writes for catalogued WEB_COOKIE_PROVIDERS only.
  • Dashboard: ConnectionRow and the Limits-page QuotaCardHeader feed providerSpecificData.cookieExpiresAt into the existing token-expiry countdown badges. Opaque cookies (claude sessionKey, grok sso) stay undated — no false precision.

No network calls, no schema migration (providerSpecificData is free-form JSON).

Verification

  • New unit suite tests/unit/web-cookie-expiry.test.ts: 9/9 pass — valid decode, url-safe/unpadded base64, cookie-header pair scan, opaque → null, malformed/non-positive/array/primitive payloads, reader guards, set/preserve-siblings, stale-drop-on-opaque-replacement, no-credential passthrough.
  • Save-path regression: db-provider-cookie-dedup-3368 + db-provider-limits suites 17/17 combined pass after the chokepoint change.
  • npx tsc --noEmit -p tsconfig.json: zero diagnostics in the five touched files.
  • ESLint: new files clean; the 4 unused-import errors in src/lib/db/providers.ts are byte-identical on the pristine base commit (verified via stash diff) and untouched here.
  • npm run check:file-size: OK.

Changed files

  • src/shared/utils/webCookieExpiry.ts (new)
  • src/lib/db/providers.ts (+40 wiring lines at the normalization chokepoint)
  • src/app/(dashboard)/dashboard/providers/[id]/components/ConnectionRow.tsx (+8)
  • src/app/(dashboard)/dashboard/usage/components/ProviderLimits/parts/QuotaCardHeader.tsx (+4)
  • tests/unit/web-cookie-expiry.test.ts (new)

@oyi77
oyi77 requested a review from diegosouzapw as a code owner August 25, 2026 11:22
…iegosouzapw#11497)

Cookies that embed a standard JWT (ChatGPT __Secure-next-auth.session-token,
Qwen/Z.ai localStorage tokens) now get their exp persisted as
providerSpecificData.cookieExpiresAt at the connection save chokepoint —
recomputed on every write so re-pasting refreshes it and an opaque
replacement drops the stale date.

Dashboard: ConnectionRow and the Limits-page QuotaCardHeader feed the new
field into the existing token-expiry countdown badges; opaque cookies
(claude sessionKey, grok sso) stay undated — no false precision.
@oyi77
oyi77 force-pushed the feat/webcookie-expiry-preview branch from a196bcd to 9513031 Compare August 25, 2026 11:28
@oyi77

oyi77 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

CI triage for the current red batch (Docs Gates / unit shards / Vitest / ESLint-suppressions): reproduced at today's merge ref (a179ffed5 + this branch) with none of this branch's content — check:docs-counts fails STRICT on README/AGENTS/llm.txt still saying "159 migrations" while code has 160, and tests/unit/agent-card-route.test.ts + tests/unit/providers-constants-split.test.ts fail at the tip itself. Inherited tip-drift, not introduced here.

This branch's own receipts stay green: web-cookie-expiry.test.ts 9/9, save-path regressions (db-provider-cookie-dedup-3368, db-provider-limits) 17/17 combined, tsc clean on touched files.

@diegosouzapw
diegosouzapw merged commit 026d26e into diegosouzapw:release/v3.8.51 Aug 25, 2026
7 of 16 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…iegosouzapw#11497) (diegosouzapw#11505)

Validated in a combined 3-PR batch worktree off release/v3.8.51 tip (a sibling PR from the same author, diegosouzapw#11495, was held out — see its own comment for the isolated finding, unrelated to this diff).
- Focused test: web-cookie-expiry.test.ts — part of batch's 94/94 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff

Thanks for closing a real trust gap — operators deserve to know a cookie is about to expire before a live request fails.
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.

Dashboard shows no expiry hint for cookies that embed a decodable JWT (e.g. ChatGPT session-token)

2 participants