Skip to content
TutujinAPI

API key security best practices: keep keys on the server, one key per project

Whoever holds your API key can spend your balance. Eight practices — server-side use only, environment variables or a secrets manager, one key per project and environment, spending limits and expiry, IP and model allowlists, rotation, watching usage — plus what to do after a leak.

Whoever holds your API key can call models on your balance. Hold three lines: keys live only on servers; keys never go into front-end code, app packages or git repositories; and every key has a spending limit. Add expiry dates, an IP allowlist and a model allowlist, and even if one key leaks, the damage is capped at that key's limit.

How keys leak

Common caseWhy it is dangerousWhat to do instead
In web or mini-program front-end codeAnyone can read it in the browser's developer toolsHave the front end call your back end, and the back end call the API
Bundled into a mobile appApp packages can be unpacked and searched for stringsRoute through your back end as well
Committed to a git repositoryIt leaks as soon as the repo goes public or is cloned; deleting the file leaves it in historyUse environment variables; treat any committed key as leaked and replace it now
Pasted into chats, tickets or screenshotsAfter a few forwards nobody knows who has itMask it before sending
Full request headers in logsPlain text in log systems is visible to many peopleRedact before logging, keeping only the first and last few characters

Eight practices

1. Call the API only from your servers

Browsers and apps call your own back end, which checks the login and applies rate limits, then calls Tutujin API with the key:

Node.js
import express from 'express'
import OpenAI from 'openai'

const app = express()
app.use(express.json())
const client = new OpenAI({ baseURL: 'https://www.tutujin.com/v1', apiKey: process.env.TUTUJIN_API_KEY })

app.post('/ask', async (req, res) => {
  // check your own session and rate-limit per user first
  const resp = await client.chat.completions.create({
    model: 'gpt-5.4-mini',
    messages: [{ role: 'user', content: String(req.body.question ?? '').slice(0, 2000) }],
    max_tokens: 500,
  })
  res.json({ answer: resp.choices[0].message.content })
})

app.listen(3000)

The key exists only in the server's environment; the browser only ever sees the answer.

2. Store keys in environment variables or a secrets manager

cURL
# set it on the server, or in a .env file that exists only on the server
export TUTUJIN_API_KEY="sk-your-key"

# make sure .env never gets committed
echo ".env" >> .gitignore

Larger teams can keep keys in a cloud provider's secrets manager or Vault and inject them at deploy time; code only reads them and never hard-codes them.

3. One key per project and per environment

For example, separate keys for "support-bot-prod" and "support-bot-test". When something goes wrong you disable one key without touching anything else, and the Logs page shows what each project spends.

4. Set a spending limit and an expiry date

The spending limit is the most a key can ever spend; it stops working once the limit is reached. Expiry dates suit temporary projects, contractors and demo environments: the key dies on schedule and nobody has to remember to delete it.

5. Turn on the IP allowlist

Only your servers' outbound IPs may call; everything else is rejected with a 403. A stolen key is then useless on someone else's machine. If your servers' outbound IP changes, update the allowlist too.

6. Turn on the model allowlist

Allow only the models your product needs; calls to anything else return a 403. A leaked key then cannot be used to call expensive models.

7. Rotate keys

Replace keys on a schedule, say every quarter: create the new key, update the server, confirm calls work, then delete the old one. Rotate as well when someone leaves the team or a contractor project ends.

8. Watch the usage

If the Logs page shows models you never use, calls in the middle of the night or a sudden spike, disable the key first and investigate second.

If you suspect a leak

  1. Disable or delete the key in the console.
  2. Create a new key, update the server configuration and redeploy.
  3. Check the calls and charges made during the leak on the Logs page.
  4. Find how it leaked: git history, logs, front-end code, chat records.
  5. If there are unexpected charges, contact WeChat support at JsnonoChat with the time range and the request id from the error message.

Keys in the console

The key list in the console shows masked keys and reveals the full key only on request. Put a new key straight into your server's environment or secrets manager; do not keep it in a text file on your laptop or in a chat.

Header formats are in Authentication and base URL, and what 401 and 403 mean is in Errors and retries. Spending limits and allowlists also help control costs — see How to control API costs.

FAQ

What should I do if a key leaks?

Disable or delete the key in the console right away, create a new one and update your server configuration, then check the calls made during the leak on the Logs page. If you see unexpected charges, contact WeChat support at JsnonoChat with the time range and the request id from the error message.

Can a web page or mobile app call the API directly?

We advise against it. Front-end code and app packages are visible to users, so a key inside them will leak sooner or later. Have the front end call your own back end, and let the back end call Tutujin API with the key.

What goes in the IP allowlist?

The public outbound IP addresses of the servers that call the API; you can add several IPs or ranges. Requests from anywhere else are rejected with a 403.

Why does the console show only part of each key?

The key list shows masked keys and reveals the full key only when you ask for it, which makes accidental leaks through screen sharing or screenshots less likely.