qvib.pro
RU

~6 min read · beginner · Updated: 2 Jul 2026 · Читать по-русски

API Keys and Secrets: A Beginner-Friendly Guide

API Keys and Secrets, Explained for Beginners

In short

An API key, a token or a database connection string is a secret: whoever knows it acts on your behalf and spends your money. There is exactly one rule — a secret never goes into code, config files or git. A leaked key gets found by bots in a public repo within minutes, while rotating it takes a minute. The engine bakes this in structurally: only placeholders like ${GITHUB_MCP_PAT} end up in the package, and the real values live in environment variables on your own machine (usually a .env file listed in .gitignore). A leaked secret is treated as compromised — you revoke it and issue a new one, and the code stays untouched. This article covers the types of secrets, a worked example of connecting GitHub, and five habits worth building early.

What it is

Many of the tools an agent connects to want proof that it is really you: GitHub, a database, Sentry, a payment provider. That proof is a secret — a password-like string the service issued specifically to you. The kinds you will run into:

Плейсхолдер ${KEY}Лежит в файлах пакетаМожно коммитить в gitУтечки нет — это только имяЗначение ключаТолько в окружении машиныВ git не попадает никогда±Утёк — немедленно ротируй
A placeholder in a file versus the value in the environment
  • API key / token — a long string like sk_live_... or ghp_.... Anyone who knows it acts as you.
  • Database connection string (postgresql://user:password@host/db) — the password is embedded inside, so the whole string is a secret.
  • OAuth — instead of a key, you log in through the browser once and the service hands the agent temporary access (often safer: no permanent key is ever created).

The rule is short and simple: a secret is like your front door key. Don't write it on the door. The "door" here is your code, config files, logs, screenshots — and above all, anything that goes into git.

Why be this strict

A leaked key is a compromised key. Once a key lands in a committed file, bots find it in a public repo within minutes and start spending your money (inference, cloud) or reading your data. That's why the engine holds a hard invariant: "a secret never lands in a file as a value; a leaked secret is treated as compromised — rotate it." And this principle isn't just written down in the rules — it's built into how the compiler assembles the package.

The cost of a leak versus the cost of a rotation
minutes
that's how long bots need to find a committed key in a public repo — and start spending your money
a one-minute job
revoking a leaked key and issuing a new one — no code changes, the placeholder stays the same
Engine invariant: a leaked secret is treated as compromised — rotate it

Placeholder versus value — the core idea

A placeholder is a stand-in name like ${DATABASE_URI_RO} or ${GITHUB_MCP_PAT}. It says "the real value gets substituted here on your machine," but it contains no value itself. The engine spreads only placeholders through the package. The real value you supply separately — in environment variables on your own computer (usually a .env file that sits in .gitignore and never travels anywhere).

An analogy: the engine package is a form that says "write your password here," not the password itself. You can show that form around, forward it, commit it — there's no password in it.

Worked example: connecting GitHub

Input. You want the agent to work with your repositories, so you enable the github MCP server. It needs a GitHub personal access token.

What the engine does:

  1. An entry appears in the spec's list of required secrets (secretsManifest) — only the name GITHUB_MCP_PAT, a "required" flag, and a link to the docs page where you create the token.
  2. At build time, .mcp.json gets a header with a placeholder, not with the token:
"headers": { "Authorization": "Bearer ${GITHUB_MCP_PAT}" }
  1. In the README and INSTALL, the engine prints a human-readable line: "GITHUB_MCP_PAT (required) — GitHub personal access token with the right scopes (repo/read)." Values: nowhere.

What you do (once, on your side):

  • Go to GitHub → Settings → create a token with minimal permissions (for instance, repo:read only, if the agent just needs to read — that's the "principle of least privilege").
  • Put it in your environment: export GITHUB_MCP_PAT=ghp_your_token (or as a line in a local .env).

Result. Through ${GITHUB_MCP_PAT} the agent substitutes your token from the environment and works with the repositories. Meanwhile, the files you commit or forward contain only ${GITHUB_MCP_PAT} — the token physically never entered the artifact. And if the token does get exposed one day, you go to GitHub, revoke the old one, create a new one; no code changes, the placeholder is the same.

The path of a secret: where the name lives, and where the value does
1. Spec
in secretsManifest — only the name GITHUB_MCP_PAT and a "required" flag
2. Package
in .mcp.json, README and INSTALL — the placeholder ${GITHUB_MCP_PAT}, values nowhere
3. Your machine
the real token — in .env, which is in .gitignore and never travels anywhere
4. Agent
substitutes the token from the environment — it physically never reaches the artifacts
From the worked example of connecting the GitHub MCP server

Five habits worth building early

  1. Secrets go in the environment or .env, never in code. And make sure .env is in .gitignore.
  2. Least privilege. If read access is all you need, don't hand over a token that can write or delete.
  3. Read-only wherever possible. For databases the engine defaults to read-only mode and a separate role — the agent can't break anything.
  4. OAuth beats a permanent key. Many presets (Vercel, Atlassian, Notion, Canva) authorize in the browser, so no permanent key is ever created.
  5. Exposed means rotate, immediately. Revoking and reissuing is a one-minute job; the fallout from a leaked key is not.

An honest boundary

The engine package is just plain text files on your disk: they can be opened and read, and that's fine — there are no third-party secrets in them, only your placeholders. The automatic "no secret leaked into the diff" check before handoff is prescribed by the engine as a rule (secrets-hygiene, mode always); enforcing it hard, by exit code, currently works only in Claude Code via a hook — in other environments it's a strict instruction.