Skip to main content
← Back to list
01Issue
BugTriagedSwamp CLI
Assigneesstack72

Relationships

#514 vault://local_encryption token does not round-trip correctly for GCP OAuth2 access tokens

Opened by bixu · 6/1/2026

When storing a GCP OAuth2 access token via swamp vault put and then referencing it via vault:// in a model's globalArguments, the token returned to the extension method fails GCP API authentication with ACCESS_TOKEN_TYPE_UNSUPPORTED.

The same token works when used directly via curl with Bearer auth. The stored token is also shorter (256 chars) than the original (261 chars) when checked after a refresh_access_token call, suggesting truncation or encoding during storage or retrieval.

Tested with both @swamp/1password and local_encryption vault backends — same result.

Reproduction:

  1. swamp vault put my-vault GCP_TOKEN "$(gcloud auth print-access-token)"
  2. Reference vault://my-vault/GCP_TOKEN in a model globalArgument
  3. Run a method that uses the token to call the GCP IAM API
  4. 401 ACCESS_TOKEN_TYPE_UNSUPPORTED
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW

Triaged

6/1/2026, 2:42:40 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack726/1/2026, 2:11:25 PM
Editable. Press Enter to edit.

bixu commented 6/1/2026, 9:56:56 AM

Root cause identified: the issue is not truncation or encoding. The model was using vault:// URI syntax in globalArguments, which is resolved at definition-load time and cached. The working pattern from ai-infrastructure uses CEL expressions (${{ vault.get(vault-name, key) }}) which are evaluated at method-execution time, ensuring a fresh token on every call.

The vault:// syntax may still have a separate round-trip issue, but the practical fix is to use CEL vault expressions for short-lived credentials like OAuth tokens.

stack72 commented 6/1/2026, 4:32:53 PM

Hey @bixu — we picked this up and tried to reproduce the round-trip failure. Here's what we tested on the current build (20260601.095735.0-sha.4fad4b5d):

1. Raw vault round-trip Stored a real GCP OAuth2 access token (260 chars from gcloud auth print-access-token) via swamp vault put, then read it back with swamp vault read-secret. Byte-for-byte match, no truncation.

2. Full expression resolution path Created a @command/shell model with vault.get(test-vault, GCP_TOKEN) in method env, executed the method, and wrote the received token to a file. Compared the file content against vault read-secret output — exact match, 260 chars both sides.

3. Special characters Tested tokens containing +, /, =, . (common in base64/OAuth tokens). All round-tripped correctly through both the vault layer and the expression resolution pipeline (CEL evaluation → sentinel resolution → shell env-var injection).

We traced the full code path (CLI arg parsing → VaultService → local_encryption provider encrypt/decrypt → vault expression resolution → CEL evaluation → VaultSecretBag sentinel resolution → Zod validation → method execution) and couldn't find a truncation mechanism.

A few things that would help us narrow this down:

  • Can you confirm this still reproduces on the latest build? (swamp update then retry)
  • When you observed the 261→256 char difference, how did you measure it? (e.g., wc -c on the method's received value, or comparing vault read-secret output against the original?)
  • Is the model using @command/shell or a custom TypeScript extension? If custom, does the extension do anything with the token before passing it to the GCP API (e.g., trim, parse, or re-encode)?
  • Could you try swamp vault read-secret <vault> GCP_TOKEN --force --json and compare the .value length against the original token to isolate whether it's the vault layer or the expression layer?

Sign in to post a ripple.