[IDE] Google OAuth refresh token is stored unencrypted in state.vscdb (antigravityUnifiedStateSync.oauthToken)

Hi team, a small suggestion from a Linux user.

What I noticed

After signing in, Antigravity IDE saves the Google OAuth token info (access token, refresh token, expiry) to:

~/.config/Antigravity IDE/User/globalStorage/state.vscdb
  table ItemTable, key: antigravityUnifiedStateSync.oauthToken

The value is base64-encoded protobuf wrapping another base64-encoded protobuf. It is encoded but not encrypted, so anyone who can read that file can recover a long-lived refresh token.

Where it happens (bundled out/main.js)

  • oauthLifecycle.persist serialises the uss-oauth topic and calls the plain storage service store().
  • The row for oauthTokenInfoSentinelKey is built by serialising {accessToken, refreshToken, expiry, tokenType, isGcpTos}, and read back by deserialising it. Neither step encrypts or decrypts.

So the password-store setting makes no difference. It stays unencrypted even with "password-store": "gnome-libsecret" in argv.json.

Why it stands out

The other Antigravity pieces on the same machine protect their credentials:

  • Antigravity 2.0 keeps its login in the OS keyring (Secret Service item Password for 'antigravity' on 'gemini').
  • The IDE’s own VS Code SecretStorage (used for extension secrets) is encrypted with the keyring (encryption.migratedToGnomeLibsecret = true).

Only this token skips both.

Steps to reproduce

  1. Sign in to Antigravity IDE, then quit.
  2. sqlite3 ~/.config/"Antigravity IDE"/User/globalStorage/state.vscdb "select value from ItemTable where key='antigravityUnifiedStateSync.oauthToken'"
  3. Base64-decode the value, then base64-decode the long inner string. The result contains the ya29. access token and the 1// refresh token in clear. (Please don’t paste your own output anywhere.)

Expected: the token is stored through VS Code SecretStorage / Electron safeStorage, or in the OS keyring the way Antigravity 2.0 does it.
Actual: it is stored encoded only.

Why it matters: backups, sync tools, dotfile repos and support bundles often copy ~/.config wholesale. A leaked refresh token stays valid until the user revokes Antigravity at myaccount.google.com.

Suggestion: route oauthLifecycle persistence through ISecretStorageService / safeStorage.encryptString, or reuse the keyring item that Antigravity 2.0 already writes.

Environment

  • Antigravity IDE 2.5.5 (VS Code 1.107.0, commit ecfbad7), official Linux x64 tarball (via the AUR antigravity-ide package)
  • Antigravity 2.0 2.18.1 and CLI 1.2.14 installed alongside
  • Arch Linux (Omarchy), Hyprland/Wayland, gnome-keyring running and unlocked

Thanks!

Hi @Psychic,

Could you please share a few details about the Antigravity version you are using? If possible, could you also provide a screen recording of the issue you are facing?