Docs menu

Secrets

Published

A secret is a value you store in Dotpane once, such as an API key or a token. A pane never holds it. The pane puts a placeholder where the value belongs, and Dotpane’s servers fill it in for that one call. The value is never sent to your browser.

How the pieces fit

Three things have to line up before a call can carry a secret:

  1. The secret, in your vault on the Secrets page, with the list of hosts it may be sent to.
  2. A secret slot in the pane’s manifest. The slot has a name, such as GITHUB_TOKEN, and the hosts it is for.
  3. A binding that connects the slot to one of your secrets. You choose it for each pane you place on a canvas, and separately for the editor’s preview.

The pane’s code then uses the slot’s name in a placeholder:

const res = await dash.fetch('https://api.github.com/user', {
  headers: { authorization: 'Bearer {{secrets.GITHUB_TOKEN}}' },
});

The placeholder names the slot, not the secret. A slot called GITHUB_TOKEN can be bound to a secret with any name, so the same pane can use a different key on each canvas.

Add a secret

Open Secrets in the sidebar and choose Add secret.

Field Rule
Name Capital letters, digits and _, starting with a letter, up to 64 characters. For example GITHUB_TOKEN. Unique in your account.
Value Up to 8 KB.
Allowed hosts 1 to 10 exact hostnames, such as api.github.com. No wildcards, ports or paths.

Once saved, the value is never shown again, by any page or API. The list shows each secret’s name, a hint, its allowed hosts, how many placed panes use it, and when a call last used it. The hint is the first four and last four characters for a value of 16 characters or more, and •••• for anything shorter. An account can hold 50 secrets.

Declare a slot in the manifest

A pane asks for a secret with a slot under secrets in its manifest.json:

{
  "name": "My GitHub",
  "size": { "default": [4, 4] },
  "secrets": {
    "GITHUB_TOKEN": { "label": "GitHub token", "hosts": ["api.github.com"], "required": true }
  },
  "network": ["api.github.com"]
}
  • The slot name follows the same rule as a secret name.
  • label describes the slot in the binding form.
  • hosts lists where this slot may be sent. Every host here must also appear, written the same way, in network.
  • required defaults to false. When it is true, a placed pane does not start until the slot is bound. The canvas shows “Connect GITHUB_TOKEN to run this pane” with a Bind button instead.

A manifest can have up to 10 slots. The manifest reference has every rule.

Bind the secret to a pane

  • On a canvas: switch to Edit, select the pane, and find Secrets in its settings. Each slot has a list of your secrets; pick one, or Not connected to unbind. Create new secret opens the Secrets page with the slot’s name filled in.
  • In the editor: Preview secrets, beside the preview, binds the slots for the preview only.

Bindings belong to one placed pane. The same pane on two canvases has two sets of bindings.

Where a placeholder works

Write it as {{secrets.NAME}}. Spaces inside the braces are allowed, as in {{ secrets.NAME }}.

Where Works? Notes
A header value Yes The value must not contain a line break.
The URL’s path and query Yes The value is percent-encoded for you.
A text body Yes A string passed as body.
A binary body No An ArrayBuffer or typed array is sent exactly as it is.
A header name No Refused with VALIDATION_FAILED.
The URL’s scheme, host or port No Refused with PROXY_URL_INVALID, because it would change where the request goes.

Something that starts like a placeholder but is not one, such as {{secrets.github_token}} with a lower-case name, or one with no closing braces, is refused with PROXY_SECRET_UNKNOWN_SLOT.

The checks on every call

Before any secret is decrypted, Dotpane checks the call in this order and stops at the first failure:

  1. The URL is https, on the default port, at most 2,048 characters, and names a host rather than an IP address. If not: PROXY_URL_INVALID.
  2. The host is in the manifest’s network. If not: PROXY_HOST_NOT_ALLOWED.
  3. Each placeholder names a slot the manifest declares. If not: PROXY_SECRET_UNKNOWN_SLOT.
  4. Each of those slots is bound on this pane. If not: PROXY_SECRET_NOT_BOUND.
  5. The host is in the slot’s hosts and in the secret’s allowed hosts. If not: PROXY_SECRET_HOST_MISMATCH.

Only then is the secret decrypted, put into the request, and the request sent by a separate service that checks the URL and address again. What each code means and what to do about it is in Error codes.

Redaction of echoed values

Some APIs repeat what you sent, for example in an error message. Before an answer goes back to the pane, Dotpane searches its body and headers for every secret value it put into that request, and replaces each one with [redacted]. It looks for the value as it is, percent-encoded, and base64-encoded.

Values shorter than 8 characters are not searched for, because short strings match too much by chance. The Secrets page marks such a secret Short value. Use a longer value where the API allows it.

Answers kept in Dotpane’s cache (the cache option of dash.fetch) are stored after redaction.

Change a secret’s value

To rotate a key, choose Edit on the secret. Enter the new value, or leave the value empty to keep the current one; you can change the allowed hosts in the same dialog. The name cannot be changed.

Bindings stay as they are, so every pane uses the new value from its next call. Cached answers made with the old value are not reused.

To rename a secret, add a new one, bind it where the old one was used, and delete the old one.

Delete a secret

Choose Delete on the secret. If no placed pane uses it, it is deleted. If some do, Dotpane answers with SECRET_IN_USE and the dialog lists those panes and their canvases. Choose Delete anyway to go ahead.

Deleting removes the value for good, along with every binding to it, on canvases and in the editor’s preview. Panes whose slot is required then show “Connect … to run this pane” until you bind another secret. In other panes, a call that uses the slot is refused with PROXY_SECRET_NOT_BOUND.

How secrets are stored

  • Encrypted with AES-256-GCM. Each value is encrypted with your account’s own data key, a random 256-bit key made when you add your first secret.
  • The data key is held by a separate key service. The database stores your data key only in wrapped form, encrypted by a key management service that runs outside the database. Without that service the stored values cannot be read.
  • Bound to its record. The encryption of each value is tied to your account and to that secret’s record. Copied to another record or another account, it fails to decrypt.
  • Decrypted only for a call. The value is decrypted on the server for the call that uses it and put into that request. It is never written to logs, error messages, the cache or a response. To save a trip to the key service on every call, the unwrapped data key is kept in the server’s memory for up to five minutes.
  • Gone with your account. Deleting your account deletes the data key, so any copy of the encrypted values left in a backup cannot be decrypted.

If the key service cannot be reached, saving a secret or making a call that uses one can fail with KMS_UNAVAILABLE. Try again shortly.

The rest of how Dotpane protects keys, panes and accounts is on the Security page.