On this page and tools
Hosted sites
Keeping keys safe on a hosted site
Your site can take payments, send email, show a map or ask an AI model a question without a single key sitting in a page. Save the key once in your dashboard. Bynefit keeps it encrypted and adds it to the request on its own servers, so no visitor can ever read it.
Availableconfig.json.
A key pasted into any of them can be copied by anyone who opens the page, and by every bot that crawls it.
Where to set it up
Open your site in the dashboard, then Settings and Keys & secrets. Managers and admins of the Space can add secrets, delete them and build secure requests, with no request to Bynefit. Only a Space admin chooses where a secret may be sent, and once a secret has somewhere to go, only an admin can replace its value. Every change is written to the Space's activity log. Adding, replacing or deleting a secret, and pointing a secure request or form webhook at a new address, is also emailed to the Space's admins and managers. The email names the secret, never its value.
Secret or public setting?
| Secret | Public setting | |
|---|---|---|
| Use it for | Payment, email, AI, database and service keys; webhook signing secrets; passwords | Things that are fine to show: a map key locked to your site's address, a publishable payment key, a support email |
| Who can read it | Nobody can view the value once it is saved: not the person who saved it, not other managers or admins, not Bynefit staff. Managers can replace a secret that is not yet sent anywhere; after an admin names its destinations, only an admin can. | Anyone visiting your site |
| How your site uses it | Bynefit adds it on the server, in a secure request or a form webhook | Your page reads it from config.json |
| Who can use it | Only the destinations a Space admin named for it. Managers and admins can build secure requests and form webhooks that send it to one of those destinations, and nowhere else. | Any page on your site |
| Limits | 50 per site, up to 8 KB each (room for a private key file) | 50 per site, up to 1,000 characters each |
Names use capital letters, numbers and underscores, starting with a letter, like STRIPE_SECRET_KEY. Names starting with BYNEFIT_ or BYNLI_ are kept for Bynefit.
A Space admin names where each secret may be sent: a host such as api.stripe.com, or a host and path such as hooks.slack.com/services/T123/B456/, which then matches only addresses under that path. A secret saved by a manager has no destinations and is sent nowhere until an admin adds one. Every change to the list is emailed to the Space's admins and managers. Never allow a shared webhook host on its own, such as hooks.slack.com or hooks.zapier.com: anyone can create an address there and receive your key. Always add the path of your own hook.
A short value or a common word is accepted with a warning: it is easy to guess, and too common to reliably keep out of pages and answers.
The list shows each secret's name, the last four characters for a long value (or a short fingerprint), when it was added or replaced and by whom, and when it was last used.
If what you type into a public setting looks like a secret key, it is refused and you are pointed to Secrets instead.
Reading a public setting from a page
Public settings are saved into your site's config.json under public. The runtime has already fetched that file, so the browser answers from its cache.
const config = await fetch('/config.json').then((r) => r.json());
const mapsKey = config.public.MAPS_BROWSER_KEY;
Secure requests
A secure request is a named, fixed route from your page to one outside service. Your page calls a Bynefit address; Bynefit adds your secret and forwards the call. You choose the service's address, the methods it accepts, the headers to add, and whether the page may add a path or a query string.
| Request | |
|---|---|
| Method and path | GET /api/sites/my-site/proxy/weather?city=Atlanta |
| Needs | Nothing from the page. It must be called from a page on the site itself. |
Service address https://api.example.com/v1/forecast?key={{secret:WEATHER_KEY}}
Methods GET
Pass the query on
const res = await fetch('https://bynefit.com/api/sites/my-site/proxy/weather?city=Atlanta');
const forecast = await res.json();
Put {{secret:NAME}} anywhere in the address after the host, or in a header such as Authorization: Bearer {{secret:NAME}}.
What keeps it safe
- The key goes only where it is allowed. Each secret lists the hosts, or host and path prefixes, it may be sent to. Bynefit refuses to add it to a request for any other address, even one a manager sets up. It is added after the request leaves the browser, so the browser never sees it. If the service sends the key back in its answer, Bynefit replaces it with
[redacted], including base64 and URL-encoded copies. - Other websites cannot borrow your visitors' browsers. A browser call must come from a page on your site's Bynefit address or its verified domain; anything else is refused, and the refusal names only the address that asked. This is not a password: a script outside a browser can claim to be your site. What bounds that caller is the limits below, so set them close to what your pages really need.
- One destination. The host is fixed when you save it. A page can add a path or a query only if you allow it, and cannot point the call anywhere else. A page cannot fill in a secret either:
{{secret:...}}in a page's own query or body is sent as plain text. - No detours. Only
httpson the standard port, never an IP address, never a private or internal network, checked again on every call against the address that was looked up. Redirects are not followed, and an address that leads back to Bynefit or to any site Bynefit hosts is refused. - Limits you set. Calls per visitor per minute (default 20), per minute in total (default 60) and per day (default 5,000). Over a limit the page gets
429. - Small and quick. Requests up to 64 KB as JSON, form fields or plain text. Answers up to 256 KB, within 8 seconds. Answers come back as JSON, plain text, CSV or a PNG, JPEG, GIF or WebP image; anything else, HTML included, is sent as plain text. An image that contains one of your secrets is not passed on at all.
Answers
| Status | error | Means |
|---|---|---|
| The service's own status | The call went through. The body is the service's answer, with your secrets redacted. | |
403 | origin_required, origin_not_allowed | The call did not come from a page on your site. |
404 | not_found | No secure request with that name, or the site is not live. |
405, 400, 413, 415 | method_not_allowed, path_not_allowed, body_too_large, type_not_allowed | The page asked for something the secure request does not allow. |
429 | rate_limited, quota_exceeded | Over one of your limits. Retry-After says when to try again. |
502, 504 | upstream_* | The service could not be reached, redirected, answered too much, or took too long. |
503 | not_configured | A secret it uses is missing. The dashboard shows the last outcome of every secure request. |
Form webhooks
A form webhook sends each answer from a form on your site to a service you choose, with your secret added on the server. Pick one form or every form on the site. With no message template, Bynefit posts every answer as JSON:
{
"event": "form.submitted",
"site": "my-site",
"form": { "id": "frm_abc123", "name": "Contact" },
"submission": { "id": "sub_9f2c...", "submitted_at": "2026-10-10T18:04:00+00:00" },
"fields": { "Name": "Ana Ruiz", "Email": "ana@example.org" }
}
Or write your own message. This one posts to a chat channel whose address is itself a secret:
Send to https://hooks.example.com/services/{{secret:CHAT_HOOK_PATH}}
Message {"text": "New message from {{field:Name}}: {{field:Message}}"}
A template can use {{field:Label}}, {{form.name}}, {{form.id}}, {{submission.id}}, {{submission.time}}, {{site}} and {{secret:NAME}}, and must be valid JSON.
What a visitor types is filled in once and never read as a placeholder, so typing {{secret:...}} into a form cannot reveal anything.
Up to five form webhooks per site. Each waits up to 5 seconds and is not retried; the dashboard shows whether the last one worked.
The check on every save
Each page, script and data file you save or upload is checked before it goes live. If it contains the value of one of your secrets, it is not published. That includes the value written as base64, URL-encoded, as hex, or split across two strings in JavaScript, and a value that reaches a page from a shared part of the site.
Keys that look private are caught too, even if you never saved them: payment secret keys, cloud access keys, code-hosting and chat tokens, AI and email service keys, Bynefit server keys,
a private key block, and long random values assigned to names like secret, token or api_key. You see the line and the first few characters, never the whole key.
- Move it to a secret. In the editor, one click saves the key as a secret and takes it out of the page. The code that used it then has to call a secure request instead, and the secret goes nowhere until a Space admin names its service.
- It is meant to be public. A key that is safe to show, such as a map key locked to your address, can be published anyway. That choice is remembered for that key on that site and written to the activity log. Check them again on the Keys & secrets page undoes it.
- Your own secrets and private key blocks cannot be published this way.
Images, video and fonts are not checked. A value shorter than 8 characters is too common to look for.
If a key leaked
- Get a new key from the service that issued it, and turn the old one off there. This is the only step that stops a leaked key from working. Deleting it from your page does not, because copies may already exist.
- Replace the secret on the Keys & secrets page with the new key (an admin, if the secret is already sent somewhere). The old value is overwritten, and secure requests and form webhooks use the new one straight away.
- Remove the old key from any page. When you save a secret whose value is already in one of your files, the dashboard tells you which.
- Check the Space's activity log for changes you do not recognise.
How it is stored
- Each value is encrypted with AES-256-GCM before it is stored. The encryption is tied to the site and the secret's name, so a value cannot be read if it is moved to another site or name.
- Values never appear in logs, error messages, emails, the activity log or staff screens. Staff see the same names and dates you do.
- Secrets are not part of your site's files, so they are never in a download, a template or a copy of your pages, and deleting the site deletes them.
Not the same as other keys
| Key | What it is for |
|---|---|
| Site secrets (this page) | Your own keys for other services, used by your hosted site through Bynefit |
| Space API keys | Your server reading Bynefit data. See Keys and review. |
| Site keys for WordPress | A WordPress site reporting to Bynefit. See Site host API. |
Never store a Bynefit API key as a site secret to call Bynefit from a page: secure requests cannot reach Bynefit's own addresses.