Skip to content

fix(quota): unwrap the Cursor safe-storage token for Grok Bot quota - #1926

Merged
iamtoruk merged 5 commits into
mainfrom
fix/grokbot-safe-storage-token
Nov 9, 2026
Merged

iamtoruk merged 5 commits into
mainfrom
fix/grokbot-safe-storage-token

Conversation

@iamtoruk

@iamtoruk iamtoruk commented Nov 9, 2026

Copy link
Copy Markdown
Member

Closes #1924. Thanks @ramonmnavarro-byte.

Cursor 3.27 and newer store the login token wrapped as cursor-safe-storage:v1:<base64>. The Cursor quota reader decrypts it; the Grok Bot quota reader sent the wrapped value as the Bearer token, so Cursor answered 401 and Grok Bot quota always showed "sign in again".

CLI

  • fetchGrokbotQuota unwraps the token with the same helpers as the Cursor reader. A locked or denied Keychain returns Cursor's locked message; a plain token is unchanged.
  • One Keychain read per codeburn quota run serves both Cursor and Grok Bot, scoped to the run, so there is one prompt, not two, and Grok Bot never prompts where Cursor would not.

Menubar

  • Grok Bot uses the shared Cursor Safe Storage unlock with the same user-action flag and stored consent. A user-initiated refresh reuses one unlock for Cursor and Grok Bot within 30 seconds, and a Deny inside that window is honoured by the second caller without another read. Background refreshes are unchanged.

Not in this PR

  • The desktop app's Grok Bot reader has the same raw-token bug and no decrypt path; it gets its own issue.
  • The Cursor Keychain reader still falls through to the second Keychain account after a Deny on the first; pre-existing, separate issue.

Tests: CLI tests for wrapped-plus-unlocked, wrapped-plus-locked, plain token and one shared read per run; Swift tests with a counting fake Keychain for the unlocked request, the locked error, and one read for Cursor then Grok Bot, including Deny. tsc clean, vitest 76/76 on the quota files, build OK. Swift compiles on CI.

Cursor 3.27+ stores its session as cursor-safe-storage:v1 ciphertext. The
Grok Bot reader sent that blob as the bearer, so every request got a 401 and
asked the user to sign in again. It now unlocks the token the way the Cursor
reader does, under the same keychain consent rule, and reports a locked
keychain with the Cursor locked message. In codeburn quota both readers share
one keychain read, so one prompt covers both. The menu bar Grok Bot service
uses CursorSafeStorage.unlock like its Cursor service.

Fixes #1924
…and Grok Bot

A user refresh unlocked the Cursor session twice, once for Cursor and once
for Grok Bot, so it could prompt twice. An allowed read now reuses the
previous allowed read's answer for 30 seconds, a Deny included. Background
reads are unchanged.
@iamtoruk
iamtoruk merged commit 40d5880 into main Nov 9, 2026
24 checks passed
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.

Grok Bot quota always 401s: fetchGrokbotQuota sends the wrapped cursor-safe-storage token without unwrapping it

1 participant