API Security Basics
Table of Contents + −
Here’s a thought that should make you a little nervous. The moment you put an API on the internet, here’s who can reach it:
- Your own app, of course, calling it the way you intended.
- And also every random person, bot, and bad actor on the planet.
- An API is just a door into your system, right? And you’ve left that door facing the whole world.
An API, short for Application Programming Interface, is just the set of endpoints your app exposes so other programs can ask it for data or tell it to do things. So when we say “secure an API”, we mean: make sure only the right callers get in, and only do what they’re allowed to do. Let’s walk through how that actually works, one layer at a time.
🎯 Why APIs Are a Target
So why do attackers love APIs so much? Here’s the thing:
- An API talks directly to your data and your actions. There’s no friendly login page in front, no buttons, just raw endpoints that read users, charge cards, delete records.
- That means one weak spot can leak everything. Miss a single check, and someone can pull every user’s email out of your database.
- And APIs are easy to poke at. An attacker can send thousands of requests a second from a script, trying different things until something gives.
A real example to keep in mind: imagine an endpoint like GET /users/123 that returns user 123’s profile. Now what if Alex changes the 123 to 124 and just gets someone else’s profile back? That’s a broken API, and that kind of bug is shockingly common.
Security is not a feature you add later
A lot of folks build the whole API first and bolt on security at the end. That’s backwards. Every endpoint you write is a new door, so you have to think about who’s allowed through it as you build it, not after.
🔒 Use HTTPS Everywhere
Before we talk about who’s calling, we have to talk about how they’re calling. And the answer should always be HTTPS:
- HTTP sends everything in plain text, so anyone sitting between your user and your server can read it. That includes passwords and tokens.
- HTTPS scrambles the traffic so nobody in the middle can read it. Scrambling data like that is called encryption.
- This matters a ton for APIs, because APIs constantly send secrets back and forth, like login tokens and API keys. Send those over plain HTTP and you’ve basically shouted your password across a crowded room.
So the rule is simple: every API endpoint serves over HTTPS, always, no exceptions. Even internal ones. If you want the deeper “why”, the HTTP vs HTTPS lesson breaks down exactly how the encryption works.
🪪 Authentication and Authorization
Okay, the line is encrypted. Now we need to know who is calling and what they’re allowed to do. Those are two different questions, and they have two names that sound almost the same:
- Authentication (often shortened to authn) answers “who are you?”. It’s checking the caller’s identity, like showing your ID card at a door.
- Authorization (shortened to authz) answers “what are you allowed to do?”. It’s checking your permissions, like whether your ID lets you into the VIP room or just the lobby.
Here’s why you need both, and why one without the other is a trap:
- Authentication alone isn’t enough. Just because we know it’s Alex doesn’t mean Alex should be able to delete other people’s posts.
- So after we confirm identity, we check permission on every action. Can this user read this record? Can they delete it? Each request gets checked.
- The classic bug from earlier, changing
123to124, is an authorization failure. The API knew who Alex was, but never checked whether Alex was allowed to see user 124.
If this split is new to you, the Authentication vs Authorization lesson goes through it slowly with more examples.
🔑 API Keys and Tokens
So how does a caller actually prove who they are on each request? Usually with a key or a token. Let’s define both:
- An API key is a long secret string you hand to a caller, kind of like a password for a program instead of a person. The caller sends it with each request, and your server checks it’s a key you recognize.
- A token is similar but smarter. A common kind is a JWT (JSON Web Token), which is a signed string that says who the caller is and sometimes what they can do. Your server can verify it hasn’t been tampered with, without looking anything up.
- The caller usually puts the token in a header, like
Authorization: Bearer <token>, on every single request.
Now the big rule with both keys and tokens: they are secrets, so treat them like passwords. That means:
- Never put a key or token in your frontend code or a public GitHub repo. Bots scan GitHub for leaked keys within minutes.
- Store them in environment variables or a secrets manager on the server side, not hardcoded in the app.
- Give them an expiry where you can, so a leaked token stops working soon. And be able to revoke a key fast if it leaks.
Leaked keys cost real money
People have woken up to thousands of dollars in cloud bills because a single API key leaked into a public repo and someone used it to start servers. Rotate your keys, set spending limits, and never commit secrets. This happens to real teams all the time.
🚦 Rate Limiting and Throttling
Even a perfectly authenticated caller can hurt you if they send too many requests. That’s where rate limiting comes in:
- Rate limiting means capping how many requests a caller can make in a given time, like “100 requests per minute per user”. Go over, and you get rejected with a
429 Too Many Requestsresponse. - Throttling is the gentler cousin: instead of flat-out rejecting, you slow the caller down.
Here’s why this is a security tool, not just a performance one:
- It stops abuse. Without a limit, one script can hammer your API and knock it over for everyone. That’s a denial-of-service.
- It blocks brute force. If someone’s trying to guess a password by sending thousands of login attempts, a rate limit shuts that down fast.
- It protects your costs. Every request costs you compute and database time, so limiting them keeps a runaway client from draining your bill.
This is a big enough topic that it gets its own lesson. Check out Rate Limiting for Security for how to actually build it.
🧪 Validate All Input
Here’s a rule to tattoo on your brain: never trust anything the client sends you. Checking that incoming data is the right shape and safe to use is called input validation. Here’s why it’s non-negotiable:
- The client can send literally anything. A real user fills in a form, sure, but an attacker sends whatever they want straight to your endpoint.
- So you check every input on the server. Is the email actually an email? Is the age a number? Is the field too long? Reject anything that doesn’t fit.
- Skipping this opens you up to injection. An injection attack is when an attacker sneaks code or commands into an input field, hoping your server runs it by mistake.
The most famous one is SQL injection. Say your code builds a database query by gluing in the user’s input directly. An attacker types something like ' OR '1'='1 into a login box, and suddenly the query lets them in without a password. The fix is to never glue user input into queries, and instead use parameterized queries, which keep the input as plain data and never as code.
A simple mental model
Treat every incoming value as guilty until proven innocent. Check its type, its length, and its format before it touches your database or your logic. Validation on the server is what counts. Frontend checks are just for user convenience, and an attacker skips them entirely.
🧩 More Good Practices
A few more habits round out a well-secured API. None of these are hard, they’re just easy to forget:
- Least privilege. Give every user, key, and service only the access it actually needs, nothing more. A read-only report tool should never have delete permission. So if it leaks, the damage is small.
- Don’t leak errors. When something breaks, send back a short, generic message. Never return a full stack trace or database error to the client, because that hands attackers a map of your system. Log the details on your side instead.
- Use an API gateway. A gateway is a single front door that all API traffic passes through. It’s a great place to handle HTTPS, authentication, and rate limiting in one spot instead of repeating that code in every service.
- Log and monitor. Keep records of who called what, and watch for weird patterns like a sudden flood of failed logins. You can’t respond to an attack you never noticed.
Here’s the whole journey of a single request passing through these layers, one check at a time:
And here’s a quick map of common threats and the defense that stops each one:
| Threat | What it is | Defense |
|---|---|---|
| Eavesdropping | Reading data in transit | HTTPS encryption |
| Fake callers | Pretending to be someone else | Authentication (keys, tokens) |
| Privilege abuse | Accessing data you shouldn’t | Authorization + least privilege |
| Brute force / DoS | Flooding with requests | Rate limiting and throttling |
| Injection | Sneaking code into inputs | Input validation, parameterized queries |
| Info leakage | Errors revealing internals | Generic error messages |
⚠️ Common Mistakes and Misconceptions
A few beliefs get developers into trouble. Let’s clear them out:
- “Internal APIs don’t need security.” They do. Networks get breached, and a service that’s “internal today” often ends up exposed tomorrow. Once an attacker is inside, an unguarded internal API is a free buffet.
- “HTTPS alone is enough.” Nope. HTTPS only protects data on the wire. It does nothing about who’s calling, what they’re allowed to do, or whether their input is malicious. It’s one layer, not the whole wall.
- “I can trust input from my own frontend.” You can’t. An attacker can call your API directly with any tool, completely skipping your frontend. So those nice validation checks in your React form mean nothing on the server. Validate again on the backend, every time.
🛠️ Design Challenge
Try this on your own to test yourself.
Imagine you’re building an API for a small banking app, with an endpoint like POST /accounts/{id}/transfer that moves money between accounts. Walk through each security layer and write down what you’d add:
- How do you make sure the caller is really who they say they are?
- How do you stop Alex from transferring money out of someone else’s account?
- How do you stop a script from spamming the endpoint?
- What do you check about the transfer amount and account id before touching the database?
Money makes the stakes obvious, so this is a great way to feel why every layer matters.
🧩 What You’ve Learned
You can now reason about securing an API end to end. Here’s what you’ve picked up.
- ✅ APIs are a prime target because they expose data and actions directly, so one weak spot can leak everything.
- ✅ HTTPS encrypts traffic so tokens and data can’t be read in transit.
- ✅ Authentication checks who’s calling, and authorization checks what they’re allowed to do.
- ✅ API keys and tokens identify callers, and they must be kept secret like passwords.
- ✅ Rate limiting stops abuse, brute force, and runaway costs.
- ✅ Input validation and parameterized queries block injection attacks like SQL injection.
- ✅ Least privilege, generic errors, an API gateway, and monitoring round out your defenses.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does HTTPS actually protect for your API?
Why: HTTPS only encrypts data in transit; you still need authentication, authorization, and input validation on top.
- 2
An endpoint returns user 123 with GET /users/123, and changing it to 124 returns someone else's profile. What kind of failure is this?
Why: The API knew who the caller was but never checked whether they were allowed to see that record, so authorization is missing.
- 3
What is the safe way to stop SQL injection?
Why: Parameterized queries keep user input as data and never as runnable code, which blocks injection.
- 4
How should API keys and tokens be handled?
Why: Keys are secrets like passwords, so keep them off the client and out of repos, and be able to rotate or revoke them fast.
🚀 What’s Next?
You’ve got the full map of API security now. Next, go deeper into two pieces that come up constantly.
- Rate Limiting for Security shows how to actually build limits that stop abuse without blocking real users.
- OAuth 2.0 Basics explains the standard way real apps handle tokens and let users grant access safely.
Once you’ve got those, you’ll be able to lock down an API the way production systems do.