Secrets
Every password, token, and keystore passphrase you type into Wirebench — a Basic auth password, an OAuth 2 client secret, a WS-Security username token, a client keystore’s passphrase — goes through the same secret store. This page covers what that means: where the value actually lives, and what does and doesn’t travel with the project.
Where a secret lives
Section titled “Where a secret lives”A secret’s value is encrypted with your operating system’s own credential store — the macOS
Keychain, Windows DPAPI, or libsecret on Linux — through Electron’s safeStorage, and kept in a
secrets.json file in Wirebench’s own data folder, not inside your project. The project file
itself never holds a value: it holds an opaque reference like sec_…, and Wirebench looks up the
value behind that reference only at the moment it’s needed, such as sending a request.
There’s no way to read a stored value back out through the UI or an exported project — only to set, replace, or clear it.
Mark a value secret
Section titled “Mark a value secret”Anywhere you see a password-shaped field — Basic auth, NTLM, a bearer token, an API key value, an OAuth 2 client secret, a WS-Security password, a keystore passphrase — it’s already a secret field: there’s no separate checkbox to turn on.
- Click the field. It opens a masked entry box.
- Type the value and choose Save. The field goes back to showing a masked placeholder with Replace…/Clear actions — never the value itself.
- To change it later, choose Replace…. This reuses the same reference rather than minting a new one, so nothing else about the project changes.
A field you typed into but never explicitly saved is still stored when you navigate away or close the form — nothing you type is silently dropped.
What is and isn’t shared
Section titled “What is and isn’t shared”Not exported, not shared, not committed as a value:
- A secret’s actual value never appears in a project file, an exported project, or a shared workspace’s git tree — only its reference does.
- The HTTP Log and the code panel redact secret-bearing headers
(
Authorization,Proxy-Authorization, and others) by default. A show/hide secrets toggle in the HTTP Log reveals them for the current session only, on request. - An OAuth 2 access token is shown in the token status panel only while that same toggle is on.
Shared, because it carries no value: the secretRef itself travels wherever the project does —
including a shared workspace. That’s by design: teammates share
which credential a request uses, not the credential. When you join a shared workspace and open a
request whose auth references a secret nobody has entered on your machine yet, its field shows
Not on this machine instead of a value, and sending fails with a message naming exactly which
credential to enter. Entering it there stores the value locally under the same reference — nothing
new is written to the shared project, so there’s nothing new to commit.
Shared, encrypted, with team secrets on: in a shared workspace, the value itself can travel too — encrypted separately for each approved machine. See Team secrets. A value that stays on your machine (team secrets off, or your machine not approved yet) shows Only on this machine next to its field.
Secret tokens and scanning
Section titled “Secret tokens and scanning”A credential doesn’t only arrive through an auth field: it gets pasted into a header, a query parameter, a body or a property. Wirebench looks for those before a manual save or a Sync commit, and offers to move each one into the secret store, leaving a token in the file.
The ${secret:name} token
Section titled “The ${secret:name} token”${secret:name} works anywhere a ${name} property does — a URL, a header, a query parameter, a
body, a message, a property’s own value. name is letters, digits and underscores, not starting
with a digit ([A-Za-z_][A-Za-z0-9_]*). The file carries only the token; when a request is sent,
Wirebench puts the stored value in its place, exactly as it was stored.
The value is kept in the same secret store as every other secret, under the token’s name, per
project and per machine: two projects can each have their own api_token, and a teammate who pulls
the project sets their own value. When nothing is stored for a name on this machine, the send is
refused rather than made with an empty value:
The secret "billing_key" is not on this machine — set it with Set Secret Token Value… (Secrets).The toast that reports it has a Set value… button, which opens that dialog on the token that was missing, its value field ready. From the command palette, Set Secret Token Value… opens it on the project of the active tab (with several projects open, the dialog lets you pick another). It lists the tokens in the project as last saved — plus, when a failed send opened it, the token that send named, even if it’s only in edits you haven’t saved yet — then any other names stored for it on this machine, each marked Set or Not on this machine; Set… or Replace… opens a masked field for the value — Enter saves, Escape cancels the edit. A name the project doesn’t use yet can be set from the field below the list, ready for a token you’re about to add. The value goes into the secret store on this machine only; the project file doesn’t change, so there’s nothing to commit.
In CI, the value comes from WIREBENCH_SECRET_<NAME> — the name upper-cased, so billing_key reads
WIREBENCH_SECRET_BILLING_KEY. See Run in CI.
A resolved value is masked like any other secret: the HTTP Log, History and run reports show
<redacted> in its place (in an XML body, escaped as <redacted>, so the body stays well
formed). Editors keep showing the token. The same goes for the value when a
server sends it back — in a WebSocket frame, text or binary, or a close reason; in a gRPC
response message, status message, or initial or trailing metadata; or in an event-stream
response’s events and comments. The response panes show it while show/hide
secrets is on; History masks it regardless.
What is found
Section titled “What is found”A value under a sensitive name, whatever it looks like:
- Headers (and gRPC metadata):
Authorization,Proxy-Authorization,Cookie,Set-Cookie,X-Api-Key. A scheme in front of the value (Bearer,Basic,Token,Digest,Negotiate,NTLM) stays in the file; only the credential after it is moved. - Query parameters:
api_key,apikey,api-key,access_token,token,key,auth,signature,sig. - JSON keys, XML element names and form fields in a body:
password,passwd,secret,token,access_token,refresh_token,id_token,client_secret,api_key,apikey,authorization— these count in headers and query parameters too. A WS-SecurityPasswordDigestis a hash, not a password, and isn’t flagged.- A JSON value counts when it’s a string or a number (
"password": 123456);true,falseandnulldon’t. - An XML element’s value is its text, or a single CDATA section with nothing but whitespace
around it (
<Password><![CDATA[…]]></Password>) — then it’s the text inside the section. A sensitive element nested inside others (<Credentials><Password>…</Password></Credentials>) is found; an element that holds other elements, rather than text, isn’t a finding itself.
- A JSON value counts when it’s a string or a number (
- Properties: any of the body names above, or a name with a credential-like word in it —
secret,token,password,passwd,credential— orkeyafterapi,secret,access,private,signing,client,authormaster(dbPassword,client_secret,apiKey; notcacheKey).
A recognisable credential shape, anywhere:
- A JSON web token: three base64url segments, the first starting
eyJ. Bearer <token>(16 characters or more) andBasic <base64>(when it decodes to auser:passwordpair).- AWS access key ids (
AKIAorASIAand 16 more characters). - PEM private key blocks (
-----BEGIN … PRIVATE KEY-----). - GitHub (
ghp_,gho_,ghs_,github_pat_) and Slack (xoxa-,xoxb-,xoxp-,xoxr-) tokens. - The password in a URL (
https://alice:hunter2@host/…,postgres://svc:hunter2@db/app) — only the password, not the user name. A URL with a user and no password (https://user@host) isn’t flagged, and neither is an obvious placeholder: a password that is all*or allx, or ispassword,pass,passwdorsecret(postgres://user:password@localhost/db).
A random-looking value under a secret-like name — 20 characters or more, no spaces, not a URL or a path, at least 3.5 bits of entropy per character — in a header, query parameter or body field whose name has one of the credential-like words above.
Wirebench looks at project and environment properties; SOAP request headers and envelopes; REST
URLs, query parameters, headers and bodies (a raw body as a whole, form and multipart text fields
one by one); gRPC metadata, on the API and on each request, and messages; WebSocket headers (on
the API and on each request), request URLs and query parameters, and saved text messages. A URL’s
query parameters are checked against the query names above, just as the query table is. Only the
first 1 MiB (1,048,576 characters) of any one value or body is scanned. A value that is already a ${…} expansion — a token, or a
property — is never a finding.
When it runs
Section titled “When it runs”- Save (Ctrl+S or the command) and Save All scan the projects they save first, and open the review when anything is found.
- A Commit from the Sync panel scans every open project first.
- Autosave, the save when a project closes, and the save on quit write without asking — those files are local. While a review is open, autosave waits for your answer.
- An automatic Sync commit with a finding in it is held instead; see Shared workspaces.
Only one review is open at a time; a second save while one is open is refused with Finish the open secret review first.
The review
Section titled “The review”The review lists one row per finding: where it is (Billing › Invoices › header Authorization),
what it looked like, and a preview — the first three characters, … and the length, never the
value. Each row proposes a name — from the header, query parameter (in the table or in the URL),
form field or property name, or else from what was found (jwt, url_password, secret) — that
isn’t already stored for the project; edit it as you like.
- Move to secret stores the value under the name and puts
${secret:name}in the file in its place. If the name already has a stored value, the row offers Replace the stored value; it isn’t overwritten until you tick it. - Keep leaves the value where it is for this session.
- Move all moves every row under its name.
- Save anyway (Commit anyway for a commit) goes ahead with the findings still there. They aren’t kept: the next manual save asks again.
- Cancel or Esc writes nothing; the edit stays unsaved.
Once every row is moved or kept, the review closes and the save or commit goes ahead.
Only the credential part of a value is replaced: Authorization: Bearer eyJ… becomes
Bearer ${secret:authorization}, and <Password>hunter2</Password> becomes
<Password>${secret:billing_password}</Password> under the name you chose. The stored value is the text exactly as it was found —
still JSON-, XML- or URL-escaped if it was — so the request sent is the same, byte for byte.
A password in a URL is replaced on its own (https://alice:${secret:url_password}@host/…), and a
value in a CDATA section keeps the section around the token.
A JSON number is replaced by a bare token: "password": 123456 becomes
"password": ${secret:password}, and the stored value is 123456. The body sent still has the
number, not a string — but the body as saved isn’t strict JSON any more, so Format and the
JSON form view can’t parse it. To keep the body valid JSON, put the token in quotes yourself; the
server then receives a string.
Keep lasts for the session only; nothing is written anywhere. A kept value is found again when it changes, or when the project is closed and opened again.
Secrets from external managers
Section titled “Secrets from external managers”If your team keeps its secrets in a vault, a cloud secret manager or a password manager, they can stay
there. A workspace maps a ${secret:name} to an entry in the manager. When a request is sent,
Wirebench runs the manager’s own command-line tool with your login, takes the value and keeps it in
memory only. Nothing is written to disk, and the value is masked like any other secret. The session’s
Toggle Show Secrets in HTTP Log reveals it in the HTTP Log the same way it reveals any other secret.
Setting it up
Section titled “Setting it up”Run Secret Sources… from the command palette (category Workspace). The dialog lists each name with its kind, its fields and where it lives:
- Shared entries are the team’s. They are saved in
workspace.yaml, so they travel with the workspace. - This machine entries are yours alone, in a file in Wirebench’s data folder. One overrides a shared
entry of the same name, or unmaps it (kind
none) for you.
Test on a row runs the lookup and answers “OK, 24 characters” or the error, never the value. The secret token dialog has Map to a source instead…, which opens the same dialog with the name filled in.
A shared entry looks like this in workspace.yaml:
secretSources: db_password: { kind: vault, path: kv/app, field: password } api_key: { kind: aws, secretId: prod/api, jsonKey: key, region: eu-west-1 } gcp_key: { kind: gcp, secret: api-key, project: my-project, version: latest } az_key: { kind: azure, vault: team-kv, name: api-key } signer: { kind: 1password, ref: 'op://Team/Signer/password' } local_pw: { kind: keychain, service: wirebench-dev, account: me }The kinds
Section titled “The kinds”Install the tool and sign in to it yourself: Wirebench never logs you in. Fields in brackets are optional.
| Kind | Tool | Fields | What it runs |
|---|---|---|---|
vault |
vault |
path, field, [mount], [namespace] |
vault kv get -field=<field> [-mount=<mount>] [-namespace=<namespace>] <path> |
aws |
aws |
secretId, [jsonKey], [region], [profile] |
aws secretsmanager get-secret-value --secret-id <secretId> --query SecretString --output text [--region <region>] [--profile <profile>] |
gcp |
gcloud |
secret, [project], [version] (default latest) |
gcloud secrets versions access <version> --secret=<secret> [--project=<project>] |
azure |
az |
vault, name |
az keyvault secret show --vault-name <vault> --name <name> --query value --output tsv |
1password |
op |
ref, starting op:// |
op read <ref> |
keychain |
security (macOS), secret-tool (Linux) |
service, account |
macOS: security find-generic-password -s <service> -a <account> -w; Linux: secret-tool lookup service <service> account <account> |
The tools run without a shell, with your own environment, so VAULT_ADDR, AWS_PROFILE and single
sign-on caches work as they do in your terminal. With jsonKey set for aws, the secret is read as a
JSON object and that top-level string member is the value. A field can’t start with -, so none can
become a flag.
The tool is found on PATH. A desktop app started from the Finder or the Dock gets a short PATH, so
on macOS Wirebench also looks in /opt/homebrew/bin and /usr/local/bin, after PATH, where Homebrew
installs vault, op and aws. A tool that is a script needing #!/usr/bin/env (gcloud, az) may
still not find its interpreter from there; start Wirebench from a terminal, or map that name on this
machine to another kind.
Approval
Section titled “Approval”A shared mapping decides which of your secrets a shared request can read, so Wirebench uses it only after you approve it on this machine, and again after any change. Until then a send that needs a mapped name is refused with a toast, Review secret sources…, which opens the dialog; its banner leads to the approval dialog. That lists every shared name with its kind and fields, and marks what was added, changed or removed since the mapping you approved. Approve records the approval for this machine; Cancel records nothing. The send is not retried for you. Your own This machine entries need no approval.
Which store answers
Section titled “Which store answers”In the app, a name in the mapping comes from its source. A name that isn’t mapped comes from the team secrets, then from this machine’s store. A mapped name never falls back to another store: if its source fails, the send fails, because a stale value left under the same name must not go out instead.
In the CLI, WIREBENCH_SECRET_<NAME> wins, then the shared mapping; see
Run in CI.
The cache
Section titled “The cache”A fetched value is kept in memory for Preferences → Secrets → Secret source cache (5 minutes by default; 0 fetches it on every send). The Clear Secret Source Cache command empties it, and so does a change to the mapping. Nothing is cached on disk.
Errors
Section titled “Errors”Each blocks the send and names the secret and its kind, never a value.
| Code | When | What to do |
|---|---|---|
secret-source-untrusted |
The shared mapping isn’t approved on this machine | Approve it in Secret Sources… |
secret-source-unavailable |
The tool isn’t found on PATH, or the process couldn’t be started |
Install it (the message links its install page), or start Wirebench from a shell that has it |
secret-source-unsupported |
The kind can’t run here | Map the name on this machine to another kind |
secret-source-failed |
The tool exited with an error, timed out (20 seconds), printed too much or nothing, or a jsonKey isn’t there |
Read the tool’s message, which is shown with secrets masked, and sign in again if it asks |
secret-source-invalid |
The entry breaks a rule, such as an empty field or a leading - |
Fix it in Secret Sources…; the send error and the Secret Sources dialog name the field |
Without running anything, the Problems list also flags these before or beside a send: Secret source is
not approved: ${secret:name} and Secret source entry is invalid: ${secret:name}. SOAP flags them
before the send; REST, gRPC and WebSocket flag them alongside it.
On Windows
Section titled “On Windows”keychain isn’t available on Windows. az and gcloud install there as .cmd wrappers, which
Wirebench doesn’t run (it never uses a shell), so azure and gcp entries are secret-source-unsupported
there. Map those names on this machine to another kind. vault, aws and op ship real executables
and work.
Limits
Section titled “Limits”- There’s no “reveal” action anywhere in the UI or in an export — a stored value can only be replaced or cleared, never read back.
- Moving a project by copying its folder carries every
secretRef, but not one value behind them — the destination machine needs its own copy of each secret entered once. Use Export project… for a project you intend to move, and expect to re-enter its secrets afterward.
Related
Section titled “Related”- Authentication — the schemes whose credentials go through this store.
- Shared workspaces — how a
secretReftravels with a synced project, and how a teammate resolves a missing value. - HTTP Log — the show/hide secrets toggle and what it reveals.