Daniel's been thinking about the lowly API key. The thing every developer touches in their first week. His question is: if API keys are so simple and flexible, and they work without browser redirects or any kind of interactive dance, why don't we just use them for everything? He wants us to dig into what an API key actually represents as an identity, what security and authorization capabilities we lose when we swap out OAuth or identity tokens for a long-lived key, and when API keys are genuinely the right choice rather than just the easiest one. He wants real examples from cloud platforms and SaaS.
The short answer is that an API key doesn't represent anything. That's the whole problem. It represents possession of a secret and nothing else. There's no identity bound to it, no scope, no expiration built in, no way to say "this key belongs to a user who should only have read access to these three buckets." It's a bearer token in the purest sense. Whoever holds it gets whatever it unlocks.
So it's a key to a door, but the door doesn't know or care who's holding the key.
Right. And the door can't ask. That's the distinction. With OAuth, when you present an access token, the resource server can look at it and say, "This token was issued to user Corn at nine fourteen AM, it expires in an hour, and it's scoped to read-only on photos." An API key just says... here's a string. Let me check if it's in my database. Yes? Come in.
And if you copy that string and paste it somewhere else, the door has no way to know.
None. The key is the entire credential. There's no binding to a device, a session, a network location. This is why every cloud provider's documentation has that paragraph in bold telling you not to embed API keys in client-side code. But the reason they have to say it is that the key itself gives no protection if it leaks. An OAuth access token can be bound to a client secret, a redirect URI, a certificate thumbprint. The token alone isn't enough. The API key alone is always enough.
Which makes it weird that we call it a "key" at all. A real key has a lock that can be rekeyed. An API key is more like... a password that you hand to a stranger and hope they don't photocopy it.
That's actually a useful way to think about it. A password that you never change and that you give to every piece of code that needs to talk to the service. And the service can't tell which piece of code is which. If you generate one API key and use it in five different microservices, and one of them gets compromised, you have to rotate that key everywhere. You've lost all granularity.
So let's go through Daniel's questions in order. First one: what identity does an API key actually represent? You're saying it represents nothing. But platforms do attach them to something, don't they?
They attach them to something, but that something varies by platform, and the attachment is administrative, not cryptographic. On AWS, an API key in API Gateway is associated with a usage plan. It's not a user. It's not a role. It's a rate-limiting bucket with a name. On Google Cloud, an API key identifies a project for billing and quota purposes. On Stripe, a secret key represents your entire account. On GitHub, a personal access token represents a user with specific scopes, but it's still a bearer token. So the answer to "what identity does it represent" is: whatever the platform decided to staple it to, and that decision is completely arbitrary.
And not portable.
Not at all. An API key from one platform means something completely different from an API key on another. There's no standard. OAuth tokens, for all their complexity, at least have a standard format. A JWT has an issuer, a subject, an audience, claims. You can look at it and decode it. An API key is opaque by design. The only thing you can do with it is present it and hope.
It is. And that leads into Daniel's second question: what do we lose when we replace OAuth or identity-based authentication with a long-lived API key? The list is longer than most people realize. We lose scoping, first of all. Fine-grained permissions. An API key is typically all-or-nothing. You get access to everything the key grants, or nothing. There's no way to say "this key can read from this S3 bucket but not write to it" unless the platform has built a separate permissions layer that sits on top of the key, which some have, but that's bolted on.
And it's bolted on differently everywhere.
Every platform reinvents it. We lose expiration. API keys don't expire by default, and even when they do, it's a manual rotation process. OAuth tokens have short lifetimes, refresh tokens, rotation policies. We lose revocation granularity. If you revoke an API key, you revoke it for everything using it. There's no way to revoke access for one service while leaving it intact for another if they're sharing the key. We lose auditability. With an API key, the log says "request came from key ABC123." With an OAuth token, the log says "request came from user Corn, acting through application PhotoSync, with scopes read and write, authenticated at this time." That's a completely different level of forensic value.
And we lose the ability to say no to specific things without saying no to everything.
That's the authorization piece. API keys are authentication without authorization. They prove you're allowed to talk to the API, but they don't say what you're allowed to do once you're talking. Platforms that rely heavily on API keys have to build authorization separately. Stripe does this with restricted API keys where you can limit permissions. But that's Stripe building an authorization layer on top of an authentication primitive. It works, but it's custom, and it's not the key doing the work.
So the key is a lobby pass, and every floor you want to visit requires a separate system that checks your badge against a list.
That's it. And the lobby pass never expires and works at every entrance and you can't tell if someone photocopied it.
When are API keys the right mechanism rather than merely the easiest one?
This is where it gets interesting, because there are real cases. The clearest one is server-to-server communication where both ends are under your control and there's no user involved. If you have a backend service calling another backend service, and both are in your VPC, an API key is fine. It's simple, it's fast, there's no redirect dance, and the attack surface is limited. The key lives in a secrets manager, it's rotated automatically, the network is isolated. That's a legitimate use.
What about public APIs where the consumer is a third-party developer?
That's trickier. If you're running a public API and you want to track usage and enforce rate limits, API keys work well for that. They're not authenticating a user. They're identifying a project or an application for metering purposes. Google Maps does this. You get an API key, you embed it in your requests, Google tracks your quota. The key isn't proving you're you. It's proving you're the same entity that made the last thousand requests so they can bill you correctly.
And the thing being protected isn't user data. It's a map tile.
Right. The sensitivity of the resource matters enormously. API keys are appropriate when the resource being accessed is low-sensitivity, or when the key is just one layer in a defense-in-depth strategy. The mistake is using them as the only layer for something sensitive.
Let's talk about the places where they're the wrong choice and everyone uses them anyway.
Client-side code. This is the one that every security guide warns about and every developer has done at least once. You're building a mobile app or a single-page application, and you need to call your own backend or a third-party API. The API key goes into the app bundle or the JavaScript. At that point, the key is public. Anyone who downloads the app can extract it. Anyone who opens the browser dev tools can see it. It's not a secret anymore. It's a string that happens to work.
And the defense is usually "we'll restrict it by referrer or IP."
Which doesn't work for mobile apps, and for web apps, referrer headers are trivially spoofed. IP restrictions help in some server-side scenarios, but for client-side, they're useless. The only real solution is to put a backend in front of the API key. Your client talks to your server, your server holds the key, your server makes the actual API call. The key never touches the client. But that adds infrastructure, and the whole reason people reach for API keys in the first place is to avoid adding infrastructure.
So the simplicity is the trap.
The simplicity is absolutely the trap. It's the easiest thing to implement and the hardest thing to secure properly. And the consequences of getting it wrong scale with the power of the key. A leaked Stripe secret key means someone can issue refunds, cancel subscriptions, pull customer data. A leaked AWS key with admin permissions means someone can spin up a crypto mining operation on your dime. There are stories of developers committing keys to public GitHub repositories and waking up to five-figure bills.
The five-figure wake-up call is practically a rite of passage at this point.
It really is. GitHub scans for exposed secrets now. They'll actually revoke your key if they detect it, and send you an email that amounts to "we saved you from yourself, please be more careful." AWS, Google Cloud, they all have secret scanning partnerships with GitHub. But that's a reactive measure. The fact that it's necessary tells you something about how often this goes wrong.
Let's dig into the cloud platform examples Daniel asked for. How do the big three handle this?
They all have API keys, and they all tell you not to use them for authentication. AWS has access keys, which are an access key ID plus a secret access key. They're used to sign API requests to AWS services. But the recommended approach is to use IAM roles, especially for anything running on EC2 or Lambda. The role is an identity. It has policies attached. It has temporary credentials that rotate automatically. The access key is the fallback for when you can't use a role, like for a third-party tool or a local development environment.
And even then, they want you to use short-lived credentials.
They want you to use STS to get temporary credentials. The long-lived access key is the thing you create when you're setting up your first CLI tool and then forget about for three years. AWS has been pushing hard to get people off long-lived keys. They added IAM roles anywhere, they added IAM Identity Center. The direction of travel is clear: keys are legacy.
What about Google Cloud?
Google Cloud has API keys, but they're explicitly not for authentication. Their documentation says it right at the top. API keys are for identifying a project for quota and billing. If you want to authenticate, you use service accounts. A service account is an identity. It has an email address. You can grant it IAM roles. You can generate keys for it, but again, the key is the fallback. The preferred approach is to use the metadata server to get an access token, or to use workload identity federation so you don't need a service account key at all.
And Azure?
Same pattern. Azure has API keys for some services, like Cognitive Services, where the key is essentially a billing identifier. For anything involving Azure AD, you use managed identities. A managed identity is an identity that Azure creates and manages for you. Your app running on an Azure VM gets a token from the instance metadata service. No key to store, no key to rotate, no key to leak. The identity is the app itself, not a string you copied from a portal.
So all three cloud providers have converged on the same answer. API keys are for metering and low-sensitivity access. Identity-based authentication is for everything else.
And they've all built infrastructure to make identity-based authentication the easy path. Managed identities, workload identity, IAM roles. The goal is to make the secure option the convenient option, because if it's not convenient, developers will reach for the API key every time.
Which they do anyway.
Which they do anyway, because the API key is what you learn first. Every tutorial starts with "generate an API key." Every quickstart guide has you paste it into an environment variable. The mental model gets set early: to talk to an API, you need a key. The idea that the key is the least secure option and you should use something else comes later, if it comes at all.
Let's talk about the SaaS side. Stripe, Twilio, SendGrid. These companies' entire business is APIs, and their primary authentication mechanism is the API key.
And they've built elaborate systems on top of it. Stripe has publishable keys and secret keys. The publishable key is safe for client-side code. It can only create tokens, not make charges. The secret key does everything. They also have restricted keys where you can limit permissions to specific resources and operations. But notice what they're doing. They're building an authorization framework on top of a bearer token. The key itself is still just a string. The restrictions are enforced server-side by Stripe's platform. If someone gets your secret key, the restrictions on your other keys don't help.
So the platform is doing the work, not the credential.
The platform is always doing the work. That's the thing people miss. An API key doesn't enforce anything. It's a lookup value. The platform receives the key, looks it up in a database, and decides what to allow based on what it finds. The key has no inherent security properties. It's not signed. It's not encrypted. It's not structured. It's just... an identifier that happens to be hard to guess.
It is, but it's the only security property the key has. A well-generated API key is a long random string. Stripe keys are something like "sk_live_" followed by a bunch of random characters. The entropy is high enough that brute-forcing is impractical. But that's the only defense. There's no cryptographic binding to anything. If the key leaks, the entropy doesn't matter.
So when Daniel asks when API keys are the right choice, part of the answer is: when you're a platform and you control the entire authorization stack on the server side, and you've built a permissions system that the key just points to.
Yes. And when the alternative, which is OAuth or some identity federation protocol, would add complexity that doesn't buy you anything. If you're an internal tool calling an internal API, and the API key is stored in a vault, rotated automatically, and scoped to exactly what that tool needs, you've addressed the key's weaknesses through operational controls. The key itself is still just a string, but the system around it is secure. At that point, replacing it with OAuth is just adding moving parts.
Moving parts that can break.
OAuth is complicated. It has grant types, redirect URIs, refresh tokens, token introspection endpoints. It's a protocol designed for a specific problem: delegating access from a user to an application without sharing the user's credentials. If you don't have a user, and you don't have a third-party application, you don't need most of what OAuth provides. You're adding complexity to solve problems you don't have.
So the decision tree is: is there a user involved? Is there a third party? Is the resource sensitive? Is the client untrusted?
That's a good framework. If there's a user, you need user identity. API keys can't give you that. If there's a third party, you need delegated access with consent. API keys can't give you that. If the resource is sensitive and the client is untrusted, like a mobile app or a browser, you need tokens that are bound to that client and can't be reused elsewhere. API keys can't give you that. But if you're server-to-server, both ends trusted, no user in the loop, and you've got operational controls around the key, an API key is perfectly fine.
What about the middle ground? The case where you have a user but the API key is scoped to that user's permissions. GitHub personal access tokens work this way.
That's a pragmatic compromise. A GitHub personal access token represents a user with specific scopes. It's still a bearer token. If it leaks, whoever has it can act as that user within those scopes. But GitHub has built enough infrastructure around it to make it workable. They show you when the token was last used. They let you set expiration. They have fine-grained tokens now that can be scoped to specific repositories. They'll even send you an email if they detect the token in a public repo. It's an API key with guardrails.
Guardrails that GitHub had to build because the primitive itself has none.
And every platform that uses API keys seriously ends up building the same guardrails. Expiration, scoping, usage tracking, revocation. They're all compensating for the fact that the underlying credential is just a string with no inherent security properties. It's a testament to how useful the simplicity is that platforms keep choosing API keys and then spending engineering effort to make them safer, rather than switching to something more secure by default.
Because the developer experience matters. Pasting a key into an environment variable is something you can do in ten seconds. Setting up OAuth for a script you're writing at two in the morning is not.
And that's the real tradeoff. It's not security versus insecurity. It's security versus friction. The API key wins on friction every time. The question is whether the thing you're protecting is worth the friction of doing it properly.
Daniel's prompt also asks what authorization capabilities we lose. We've covered scoping and expiration. What about delegation?
Delegation is a big one. With OAuth, a user can grant limited access to an application without sharing their credentials. The application gets a token scoped to what the user approved. The user can revoke that grant without changing their password. With an API key, there's no concept of delegation. The key either works or it doesn't. If you give someone your API key, you've given them everything the key can do, and the only way to take it back is to revoke the key entirely, which breaks everything else using it.
And there's no consent screen. No moment where the user says "yes, I'm okay with this application reading my email but not sending it."
None. The API key model assumes that whoever has the key is authorized to do whatever the key allows. There's no user in the loop, no approval step, no audit trail of grants. It's a model designed for automation, not for user consent.
Which is why it works for automation and fails for anything involving people.
Right. A cron job doesn't need to click "allow" on a consent screen. A CI/CD pipeline doesn't need to review scopes. For machine-to-machine communication, the API key's lack of user-centric features is a feature, not a bug. The problem is when people use API keys in user-facing contexts because it's easier than setting up OAuth.
Let's talk about rotation. You mentioned it earlier, but it's worth unpacking. Why is key rotation so hard in practice?
Because an API key has no built-in transition period. With OAuth, you can issue overlapping tokens. The old one works, the new one works, you switch over, the old one expires. With an API key, if you revoke the old key before the new one is deployed everywhere, you have an outage. If you deploy the new key alongside the old one, you have to coordinate the switch. There's no standard way to do it. Every team builds their own process, and most teams don't build one at all. The key gets created, it gets used, and three years later it's still active because nobody wants to touch it.
And the longer it lives, the more places it's been copied to.
The more people who have seen it. A key that started in a config file might end up in a Slack message, a support ticket, a log file, a backup. Every copy is a potential leak. Rotation limits the blast radius. But rotation is painful, so it doesn't happen.
We've got a credential that's simple, flexible, works everywhere, and is a nightmare to manage at scale. That feels like the summary.
That's the summary. The API key is the "works on my machine" of authentication. It's perfect for the individual developer prototyping something. It becomes a problem the moment you have a team, or a production environment, or anything worth protecting.
What's the worst API key leak you've actually seen in the wild?
There was a case a few years ago where a security researcher found an AWS key hardcoded in a mobile app for a smart home device. The key had full admin access to the company's AWS account. With it, he could control every device the company had ever sold. Unlock doors, disable alarms, access cameras. The key was in the app binary. Anyone who downloaded the app had it.
The key that unlocks every door, shipped inside every door.
That's the phrase. And the company's response was to revoke the key and push an update. But the underlying problem was that someone, at some point, decided that embedding an admin key in client-side code was acceptable. And it probably happened because they were trying to get something working, and the key was the quickest way, and it worked, and they moved on.
And the key stayed.
The key always stays.
Hilbert: I've got a nephew who does platform security for one of the big payment processors. He says the same thing. The keys never die. He once found a production key that had been active for eleven years. Eleven years. It had outlasted three CEOs.
Eleven years is longer than some marriages.
Hilbert: He traced it back to an intern who'd been asked to set up a test integration. The intern generated a key with full production access because nobody told him not to. The intern left. The key stayed. It was in a config file that got copied into the production deploy script. Nobody knew it was there. For eleven years, that key could have drained the company's merchant accounts, and the only thing protecting it was that nobody had found it.
That's the organizational problem I keep coming back to. The key outlasts the person who created it. It outlasts the project it was created for. It becomes invisible.
Hilbert: My nephew says they find keys in log files all the time. Someone adds a debug line to print the request headers, forgets about it, and suddenly the API key is in the log aggregation system. Which is searchable by half the engineering org. He says the number of people who have accidentally seen a production secret is probably higher than the number who haven't.
There's no way to know.
Hilbert: No way to know. That's what keeps him up. He says the only thing worse than a key you know is leaked is a key you don't know is leaked. And most keys are in that second category. He's not a cheerful man, my nephew. But he's not wrong.
The log file problem is especially bad because it's so easy to do. You're debugging an authentication issue, you add a log statement, you fix the issue, you forget the log statement. The key is now in Splunk or Datadog or whatever, persisted indefinitely, indexed, searchable. And log systems are not designed as secret stores. They're designed to be accessible.
The key leaks not through malice but through... convenience.
Through the normal course of development. That's what makes it so hard to prevent. It's not an attacker breaking in. It's a developer trying to get their job done.
Hilbert: My nephew has a rule. He says if you can't rotate a key in under five minutes without anyone noticing, the key is too powerful. Most teams can't rotate their keys at all.
Five minutes is a high bar.
Hilbert: It's not a high bar. It's the bar. If a key leaks on a Friday night, you don't want to be the person who has to spend the weekend rotating it across forty-seven services. You want to run a script and go back to dinner. Most places, the script doesn't exist. The key is hardcoded in three places, referenced in two more, and one of them is a server that Bob set up before he left and nobody knows how to access.
Bob's server. Every organization has one.
Hilbert: Bob's server is where keys go to live forever.
The nephew's view is that API keys are fundamentally unmanageable at scale.
Hilbert: His view is that they're manageable if you treat them like radioactive material. Short half-life, tracked inventory, containment protocols. Most places treat them like office supplies. That's the gap. He says the technology is fine. The operational practices are what fail. But he also says that if your security depends on operational practices being perfect, you've already lost. The credential itself should do some of the work. API keys don't.
That's the argument for short-lived credentials. A token that expires in an hour limits the damage. Even if it leaks, the window is small. The problem is that issuing short-lived credentials requires an identity infrastructure. You need something that can vouch for the requester and mint the token. That's what the cloud providers have built with IAM roles and managed identities. But if you're not on a cloud platform, or you're using a third-party service that only supports API keys, you don't have that option.
The API key persists because it's the lowest common denominator.
It's the one thing every service supports. REST API, GraphQL, gRPC, doesn't matter. You can pass an API key in a header. It works everywhere. That universality is valuable. It means you can integrate with anything without negotiating protocols or setting up federation. The cost is that you're using the least secure option available.
Which brings us back to Daniel's framework. When is it the right choice? When universality and simplicity matter more than the security properties you're giving up, and when the resource being protected doesn't justify the overhead of something stronger.
When you've built the operational controls to manage the key responsibly. Rotation, scoping, monitoring, revocation. If you can't do those things, the key is a liability no matter what it's protecting.
The misconception people hold about API keys is that they're a form of authentication. They're not. They're a shared secret that identifies a billing account or a usage quota. Calling them a key makes them sound like they unlock something specific. They don't. They're a password that you hand out and can't easily take back.
The correction is that authentication requires identity. A key has none. If you need to know who is making the request, or what they're allowed to do, or whether they still have permission, you need something that carries identity claims. An API key carries none of that. It's a pointer to an entry in a database, and everything else is up to you.
The question I keep coming back to is whether we'll ever get rid of them. Every platform is pushing toward identity-based auth, but the API key is still the first thing in every quickstart guide.
It'll stick around for the same reason passwords have stuck around. It's simple, it's universal, and the alternatives require infrastructure that not everyone has. The direction of travel is toward short-lived tokens and managed identities, but API keys will be with us for a long time. The best we can do is understand what they are and what they aren't, and stop using them for things they were never designed to protect.
Thanks to Hilbert Flumingtop for producing, and for the nephew's perspective on the radioactive half-life of office-supply credentials.
This has been My Weird Prompts. If you want to send us your own questions, email the show at show at my weird prompts dot com.
We'll be back soon.