APIs are everywhere. They connect your frontend to your backend, your application to third-party services, your microservices to each other. And because they are everywhere — and because they carry real data and execute real actions — they are one of the most targeted surfaces in modern application security.
The bad news is that most APIs are insecure by default. Security is not something that happens automatically when you build an API — it requires deliberate decisions at every layer of the stack. The good news is that the vulnerabilities are well-understood, the fixes are achievable, and you do not need an unlimited budget to get API security right.
This guide walks through how to secure APIs practically — covering the areas that matter most, with concrete examples you can act on.
Who this is for: Developers building or maintaining APIs, engineering leads setting security standards, and security teams looking for a structured approach to API risk. No prior security expertise required.
Why API Security Is Different
API security is not just application security applied to APIs. There are characteristics of APIs that create unique risk profiles that traditional web application security testing does not fully address.
APIs are designed to be machine-readable and programmatic. That means they expose functionality and data in structured, predictable formats — which makes them easier to attack systematically. An attacker probing your API can enumerate endpoints, fuzz parameters, and test authorisation logic at scale, automatically, without triggering the kind of alerts a human user might.
APIs also tend to be more permissive than web interfaces. UI flows enforce business logic visually — you can only click what is presented to you. APIs have no such constraints. A client can call any endpoint, with any parameters, in any order. The security logic has to live in the API itself.
Finally, APIs are often under-documented and under-monitored. Teams frequently do not have a complete inventory of their own APIs — particularly in organisations that have grown quickly or have multiple teams building independently. You cannot secure what you cannot see.
Step 1: Know What You Have
Build and maintain an API inventory
Before you can secure your APIs, you need to know what they are. This sounds obvious — but in practice, many organisations discover APIs they did not know existed during security engagements.
Your inventory should capture:
- Every API endpoint exposed internally and externally
- What authentication method each endpoint uses (or does not use)
- What data each endpoint returns — particularly anything sensitive
- Which services and clients consume each endpoint
- Whether the API is documented (and whether the documentation is current)
Tools like Postman, Swagger/OpenAPI specs, and API gateways can help with discovery. For larger environments, consider automated API discovery tools that monitor traffic to surface undocumented endpoints.
Watch out for shadow APIs — undocumented endpoints that were built for a specific purpose and forgotten. These are often the most dangerous, because they receive no maintenance, no security updates, and no monitoring.
Step 2: Get Authentication Right
Authentication is the front door of your API. If it is broken or missing, nothing else matters. Broken authentication is consistently one of the most commonly exploited API vulnerabilities, and it takes more forms than most developers expect.
Use strong, standard mechanisms — and apply them consistently
The most common authentication approaches for APIs are API keys, OAuth 2.0, and JWT (JSON Web Tokens). Each has appropriate use cases. The critical point is that authentication must be enforced on every endpoint — not just the ones that feel sensitive.
For API keys:
- Treat them as secrets — never expose them in URLs, logs, or client-side code
- Rotate them regularly and invalidate compromised keys immediately
- Scope them to least privilege — a key that only needs read access should not have write access
For JWT:
- Always validate the signature — never trust the payload without verification
- Reject tokens with the
alg: noneheader — this is a known attack vector - Set short expiry times and implement token refresh flows
- Do not store sensitive data in the JWT payload — it is encoded, not encrypted
# Bad: API key exposed in URL GET /api/users?api_key=sk_live_abc123 # Good: API key in Authorization header GET /api/users Authorization: Bearer sk_live_abc123
Step 3: Enforce Authorisation at Every Layer
Authentication answers "who are you?" Authorisation answers "what are you allowed to do?" These are separate concerns, and both must be implemented correctly. In practice, authorisation failures are more common and harder to spot than authentication failures.
Implement object-level and function-level authorisation checks
The two most common API authorisation failures are Broken Object Level Authorisation (BOLA) and Broken Function Level Authorisation (BFLA). They appear in the OWASP API Top 10 as the top two vulnerabilities — because they are the most prevalent.
BOLA (also called IDOR): A user can access another user's data by manipulating an object identifier in the request — for example, changing /api/invoices/1042 to /api/invoices/1043 and receiving someone else's invoice.
BFLA: A user with a standard role can perform administrative actions by calling admin endpoints directly — for example, calling DELETE /api/users/456 even though the UI does not show them a delete button.
The fix for both is the same in principle: every API endpoint must check not just that the caller is authenticated, but that this specific caller is authorised to perform this specific action on this specific resource. Do not rely on the frontend to hide functionality — the backend must enforce it independently.
# Vulnerable: checks authentication but not object ownership def get_invoice(invoice_id): if not current_user.is_authenticated: return 401 return Invoice.get(invoice_id) # Any user can access any invoice # Secure: verifies ownership before returning data def get_invoice(invoice_id): if not current_user.is_authenticated: return 401 invoice = Invoice.get(invoice_id) if invoice.owner_id != current_user.id: return 403 # Forbidden return invoice
Step 4: Validate and Sanitise All Input
Every piece of data that arrives at your API from an external source is untrusted. That includes request bodies, query parameters, path parameters, headers, and file uploads. Failing to validate and sanitise input is the root cause of injection attacks — SQL injection, command injection, NoSQL injection, and XML injection all stem from the same failure: trusting user input.
Validate type, format, length, and range — then sanitise
- Type validation: Reject input that does not match the expected data type. If you expect an integer, reject strings.
- Format validation: Validate formats like email addresses, UUIDs, and dates against a strict pattern. Reject anything that does not match.
- Length limits: Set maximum lengths on all string inputs. Unbounded input enables denial-of-service attacks and buffer issues.
- Allowlisting over denylisting: Define what is acceptable rather than trying to block what is not. Allowlists are finite; attack payloads are not.
- Parameterised queries: Never construct database queries by concatenating user input. Use parameterised queries or an ORM that handles escaping.
Validate on the server, always. Client-side validation improves user experience but provides zero security. An attacker will bypass your frontend and call your API directly.
Step 5: Control Data Exposure
A common API mistake is returning more data than the client needs. An endpoint that returns a full user object — including password hashes, internal IDs, admin flags, and private fields — when the client only needs a display name and email is exposing data it has no reason to expose.
This is Excessive Data Exposure, OWASP API3. It is usually not malicious — developers return full objects because it is easier, and assume the client will ignore what it does not need. The problem is that an attacker receives the full response and does not ignore it.
Return only what the client needs — nothing more
- Define explicit response schemas for every endpoint. Do not return ORM objects directly.
- Use serialisation layers or DTOs (Data Transfer Objects) that explicitly map what fields to include in the response.
- Audit your API responses regularly — what fields are being returned that do not need to be?
- For GraphQL APIs, implement field-level authorisation. Just because a field exists in the schema does not mean every user should be able to query it.
Step 6: Implement Rate Limiting and Throttling
Without rate limiting, your API is open to brute force attacks on authentication endpoints, credential stuffing, enumeration attacks, and denial-of-service through resource exhaustion. Rate limiting is one of the easiest controls to implement and one of the most frequently overlooked.
Limit requests at multiple levels
- Per IP: Limit the number of requests from a single IP address within a time window
- Per API key or user: Limit requests per authenticated identity, regardless of IP
- Per endpoint: Apply stricter limits to sensitive endpoints like login, password reset, and OTP verification
- Implement exponential backoff: After repeated failures, increase the delay before allowing further attempts
- Return 429 Too Many Requests: Not 200 with an error message — the correct HTTP status code signals to clients and monitoring systems what is happening
Login endpoints with no rate limiting are trivially brute-forceable. If your authentication endpoint accepts unlimited requests per second, an attacker with a credential list and a script can test thousands of combinations in minutes.
Step 7: Use HTTPS Everywhere — and Configure It Correctly
All API traffic should be encrypted in transit using HTTPS. This is table stakes in 2026 — there is no acceptable reason for an API to operate over plain HTTP. But HTTPS is not binary: a misconfigured HTTPS implementation can still leave you vulnerable.
- Enforce TLS 1.2 as a minimum. Disable TLS 1.0 and 1.1.
- Use strong cipher suites — disable known-weak ciphers like RC4 and DES
- Validate certificates properly in API clients — do not disable certificate verification in code
- Implement HSTS (HTTP Strict Transport Security) headers to prevent protocol downgrade attacks
- Redirect HTTP to HTTPS at the infrastructure level, not just in application code
# Bad: certificate verification disabled in client code requests.get(api_url, verify=False) # Good: certificate verification enabled (this is the default) requests.get(api_url) # verify=True by default
Step 8: Log, Monitor, and Alert
Security controls reduce risk — they do not eliminate it. Logging and monitoring are what allow you to detect when something goes wrong, investigate after an incident, and demonstrate compliance. Without them, you will not know you have been breached until a third party tells you.
Log what matters — without logging what you should not
Log these:
- Authentication events — successes and failures
- Authorisation failures — when a user is denied access
- Unusual request patterns — high volumes, unexpected endpoints, unusual user agents
- Input validation rejections — signs of scanning or fuzzing activity
- Rate limit triggers
Do not log these:
- Passwords, tokens, API keys, or any credentials — even in error messages
- Full request bodies that may contain sensitive personal data
- Payment card numbers or health information
Set up alerts for anomalies — a spike in 403 responses, a single IP hitting dozens of endpoints, or a sudden increase in 5xx errors. These are often early indicators of an active attack or a misconfiguration being exploited.
Step 9: Test Your APIs Like an Attacker Would
Documentation and code review will only take you so far. The only reliable way to know how your API behaves under adversarial conditions is to test it adversarially. This means going beyond automated scanning — which is useful but not sufficient — and including manual testing that exercises business logic, authorisation flows, and edge cases that scanners cannot reason about.
At a minimum, your API security testing should cover:
- Authentication bypass attempts — can you access endpoints without a valid token?
- BOLA / IDOR testing — can you access another user's objects by manipulating IDs?
- Privilege escalation — can a standard user perform admin actions?
- Input fuzzing — do unexpected inputs cause errors that reveal information?
- Rate limit validation — are limits actually enforced, or just configured?
- Data exposure review — are responses returning fields that should not be public?
- Mass assignment testing — can you modify fields by including them in a request body that the API should not accept?
Automated tools are a good starting point, not a finish line. Tools like OWASP ZAP, Burp Suite, and purpose-built API security scanners will catch common issues. But BOLA, BFLA, and business logic vulnerabilities require a human tester who understands what the API is supposed to do.
The API Security Checklist
Before you ship — and as an ongoing audit
Securing an API is not a one-time project. It is a discipline — built into how you design, build, test, and monitor every endpoint you ship.
Where to Start If You Are Overwhelmed
If your APIs have never had a structured security review, the list above can feel like a lot. It is. But you do not have to solve everything at once.
Prioritise in this order: authentication first, then authorisation, then input validation, then rate limiting. These four controls address the majority of real-world API breaches. Everything else is important — but if you get these four right, you have already closed the most dangerous attack paths.
If you are unsure where you stand, an independent API security review will give you a clear, prioritised picture. Not a generic report — a specific assessment of your actual API surface, with findings ranked by real-world exploitability and remediation guidance your team can act on immediately.
Not sure how secure your APIs actually are?
Book a free, no-obligation consultation. We will talk through your API architecture, identify where the highest-risk areas are likely to be, and outline what a focused security engagement would look like.
Book Free Consultation →