Keep API keys and passwords safe with project secrets

Set secrets on App settings or let AI set them, values written for you, why to publish again after a change, and the front-end key and .env traps.
The sites AI builds for you keep getting smarter: they talk to LINE, send email, call another AI. Each of those needs an API key or a password, and then comes the question of where to keep it. Many AIs simply put the key in the code, or pack a .env file into the ZIP, which is an easy way to leak it without noticing.
This guide shows how to keep API keys and passwords safe with your project's App settings (secrets) on BrewInTH: setting them yourself, letting the AI set them, the values the platform writes for you, and the traps people fall into most.
In short
✅ Secrets live on the project's App settings tab, encrypted at rest, and reach your app as environment variables
✅ After changing a value, publish again so the app sees it
✅ Databases, Redis and app email get their connection values written for you; no copying passwords by hand
✅ A key inside front-end code is visible to everyone; a secret key must be used server-side only
✅ Never put a real.envin your ZIP, and never let the AI write keys into the code
What secrets are, and why not in the code
A secret is a value your app needs that nobody else should see: a database password, a payment provider's API key, a LINE token, a key that signs sessions.
Written into the code, it travels wherever the code goes: ZIP files passed around, a GitHub repository, a screenshot sent to a friend, a chat with another AI. Once it leaks you have to replace the key everywhere it is used.
The right way is to keep values apart from code. The code reads them from environment variables, such as process.env.LINE_TOKEN (Node), os.environ["LINE_TOKEN"] (Python) or getenv('LINE_TOKEN') (PHP), and the real values are stored at BrewInTH.

Set a secret yourself in the console
- Open the project and go to the App settings tab, to the App settings section with the Name and Value fields.
- In Name, type an upper-case name such as
LINE_CHANNEL_TOKEN. - In Value, paste the real value and press Save.
- Change an existing value with Edit.
Name rules: start with an upper-case English letter, then upper-case letters, digits or _, up to 64 characters. A few names the system uses itself are refused, such as PATH and NODE_OPTIONS.
Worth knowing: on this page the project owner sees every value in plain text, so checking and editing is easy. Be careful when sharing your screen, in an online meeting, or when sending a screenshot to someone; close this tab first.
Let the AI set them
With a coding agent and your BrewInTH link and token, you do not have to copy values one at a time. Tell the AI:
This app needs LINE_CHANNEL_TOKEN and OPENAI_API_KEY.
- Never write the real values into the code or any uploaded file; read them from environment variables.
- Set both as project secrets on BrewInTH. I will paste the values in my next message.
- Make a .env.example with the names only, no real values.
- When done, publish again and check that the app can read them, without printing the values in logs or in this chat.
The AI sets values through the Set secrets such as DB_PASSWORD permission. The Read all app settings permission also lets it read values back. A token from Create the AI link and token (automatic) has both. If the job does not need to read values, issue the token with Customize permissions and leave the read permission unticked; see how to set up your coding agent.
To remove a name you no longer use, ask an AI with the set-secrets permission to delete it. A deleted value disappears from the running app with the next release.
Values the platform writes for you
Many values need no setting at all. BrewInTH writes them when you create or connect a service.

- PostgreSQL:
DATABASE_URL, the setDB_HOSTDB_PORTDB_DATABASEDB_USERNAMEDB_PASSWORD, andPGHOSTPGUSERPGPASSWORD… - MySQL / MariaDB:
MYSQL_URL, the sameDB_*set, andMYSQL_HOSTMYSQL_USERMYSQL_PASSWORD… - MongoDB:
MONGODB_URL,MONGODB_URI,MONGO_URL,MONGO_URI - Redis:
REDIS_URL,REDIS_HOST,REDIS_PORT,REDIS_PASSWORD - App email: on the Email page press *Use in the app (write MAIL_)**; the platform writes
MAIL_HOST,MAIL_USERNAME,MAIL_PASSWORDand the related values, with a fresh password
Not sure which database to pick? See choosing a database.
Changed a value? Publish again
Your app reads its secrets once, when it starts. After you change a value in the console, the running app keeps the old one until the next release. Two ways:
- On the Releases tab, choose the latest ZIP and press Build & publish
- Or tell the AI in the same chat: "I changed a value in App settings, please publish again with the latest settings"
The upside: replacing a key (say the old one leaked) needs no code change at all. Change the value, publish again, done.
Common traps

1. A key in front-end code is public
Code that runs in the browser (HTML, the JavaScript of React, Vue or a static page) is sent to every visitor. Anyone can view the source and find the key. Variables like VITE_… or NEXT_PUBLIC_… are baked into the JavaScript files at build time too.
The rule: a key that can cost money or open data (an AI service key, a payment provider key, a LINE token) belongs in server-side code only. Have the AI build a small API in your app: the page calls your API, and your API calls the outside service with the key.
2. A static site has nowhere to keep a secret
A site made only of HTML, CSS and JavaScript has no server-side program, so App settings do nothing for it. If you need a secret key, it has to be an app, such as Node or Python with an API part.
3. A .env file inside the ZIP
Upload a ZIP with a .env in it and the preflight check warns you to put secrets in App settings instead. Do that: remove .env from the ZIP and keep only a .env.example with names.
The Upload and go live page (BETA) handles this for you: values from a .env at the project root become project secrets, and the file itself is not uploaded.
4. Secrets are for run time, not build time
The build step does not receive the project's secrets. Values the build needs, such as VITE_API_URL, must be in the project's files (e.g. .env.production) and must be fine to make public anyway. Real secrets are read by the app while it runs.
What BrewInTH does for you
- Secrets are encrypted at rest (AES-256-GCM)
- Reads and changes are recorded by name only, never the value
- Values belong to one project; other projects in your account cannot read them
- An AI token that can read secrets can only be issued by the account owner
Frequently asked questions
A key leaked. What now?
Go to the service that issued it (its API key page), revoke the old key and create a new one at once, then update it in App settings and publish again. If the key was ever in a repository, treat it as leaked even if you deleted it later.
How long can a secret be?
Up to 32,768 characters per value, enough for a private key or a service account's JSON file.
Can I paste a whole .env file at once?
The console sets one value at a time. For many values, let a coding agent set them all in one go, or use the Upload and go live page, which reads the .env in the files you send. Do not hand the AI secrets of other systems that have nothing to do with this app.
Do I need to send secrets to the team when asking for help?
No. Secrets are encrypted at rest; when asking the team for help, never send values in the chat. The names are enough.
Can I keep non-secret settings in the same place?
Yes, such as APP_ENV or TIMEZONE. Same page, and your app reads them the same way.
Summary
Secrets do not belong in the code, in the ZIP or in front-end code. Let the code read environment variables, keep the real values on the App settings tab or let the AI set them, leave database and email values to the platform, and publish again every time you change a value.
Start your first project for free →
