API key vs secret vs token: what is the difference?
In one sentence:A secret is any credential you keep hidden; an API key is a long-lived secret identifying your app, and a token is a short-lived secret identifying a user or session.
What it actually is
“Secret” is the umbrella term: any piece of information that grants access to something and needs to stay hidden, a password, a private key, a database connection string, all of it. An “API key” and a “token” are both specific kinds of secret, which is why the phrase “every API key is a secret, but not every secret is an API key” is exactly right.
Think of a secret as anything you wouldn’t leave sitting on your desk. An API key is like a labeled keycard for one specific building, say the Stripe building or the OpenAI building. It identifies which app or account is knocking on the door, and it usually stays valid for a long time, until you or the provider revokes it. A token is more like a wristband at a concert: issued for one visit, often scoped to a single user or session, and built to expire, sometimes in minutes.
Concretely: OPENAI_API_KEY and STRIPE_SECRET_KEY are API keys, long-lived credentials that say “this app is authorized to call this service.” A JWT you get back from Supabase Auth after a user logs in, or a GitHub OAuth access token, is a token, tied to a session or a person, meant to run out.
Why your AI just did this
When your agent wires up a service like Stripe, Resend, or OpenAI, it needs a credential proving your app is allowed to make requests. That’s the API key. The agent will typically ask you to paste one into a .env file and read it in code as process.env.STRIPE_SECRET_KEY, and it should add .env to .gitignore in the same step, because that file is now full of secrets.
When your agent builds login or signup, it’s solving a different problem: proving who a specific user is, not which app is calling. That’s where tokens show up: session tokens, JWTs, refresh tokens, each with an expiry baked in so a stolen one goes stale.
When you’ll run into it
You’ll see it in error messages like “Invalid API key provided” from Stripe, “401 Unauthorized” from a fetch call, or “Missing OPENAI_API_KEY environment variable” when your app boots without one set. You’ll see it in setup wizards that say “add your API key to continue” when connecting a new service. You’ll see it when GitHub’s push protection blocks a commit because it spotted something that looks like a live key in your diff. And you’ll see the token side of things when a user gets logged out unexpectedly because their session token expired, or when your agent talks about “refreshing the access token.”
What to check
.env(or.env.local) is listed in.gitignorebefore you ever run the app, not after- Secret keys live only in server-side code or your hosting platform’s environment variable dashboard, never shipped to the browser
- You’re using the provider’s test/sandbox key while building, and only switch to the live key at launch (Stripe, for example, has both)
- If a key or token leaks (pushed to GitHub, pasted in a screenshot, shared in chat), you regenerate it immediately from the provider’s dashboard; treat “maybe someone saw it” as “someone saw it”
- Where the provider supports it, you restrict the key: by IP, by domain, or by usage cap, so a copied key can’t be used from anywhere for anything
Say it like a dev
Instead of: “put the password in the code” Say: “store this as an environment variable, not hardcoded in the file”
Instead of: “is it safe to show you this key” Say: “is this a publishable key or a secret key, and can it go in client-side code?”
Instead of: “make it so I stay logged in forever” Say: “use a short-lived access token with a refresh token, not a key that never expires”
People actually ask
“If I pay for an API key based on the number of requests, what stops someone from stealing it and running up my bill?”
Nothing built into the key itself. That's why providers give you separate tools: usage caps and alerts you set in your dashboard, IP or domain restrictions on the key where supported, and the ability to revoke and regenerate the key in seconds. The habit that actually protects you is never putting the key anywhere a stranger could read it, like client-side code or a public repo, and checking your usage dashboard occasionally instead of only after the bill arrives.
“Is every API key a secret, but not every secret is an API key?”
Yes. "Secret" is the category for anything that grants access and must stay hidden: passwords, database credentials, private keys, tokens, and API keys all qualify. An API key is one specific shape of secret: a credential that identifies an application to a service, usually long-lived, often tied to billing.
“What's the real difference between a token and an API key?”
Lifespan and what they identify. An API key usually identifies an app or project and stays valid until revoked. A token usually identifies a specific user or session and is built to expire quickly, which limits the damage if one gets copied.
Related terms
Glim can explain your sessions, live.
The app watches your coding agent and narrates it in plain words. Waitlist is open.