
API Security Best Practices: Protect Your SaaS from Day One
Security is the infrastructure investment that founders delay until something goes wrong. The reasoning is understandable: you are moving fast, building features, and security feels like a problem for companies with actual users. Then an unsecured API endpoint leaks your beta users' email addresses, or a script kiddie takes down your staging environment while you are in a pitch meeting, and the conversation about "doing security properly" becomes urgent and expensive.
The cost calculus on API security is simple. A day-one security implementation costs 10-20% additional engineering time per sprint. A post-breach remediation — including the forensic investigation, notification requirements under GDPR or CCPA, customer trust damage, and the rewrite of insecure code — costs 10-100x more. For a startup at any stage, this trade-off is obvious.
This guide covers the API security fundamentals every SaaS product needs before it accepts real users. P2C implements these as standard for every production SaaS engagement, backed by ISO 27001:2022 certified processes.
Authentication: Getting Identity Right
Authentication is the most consequential security decision you make. Get it wrong and everything built on top of it is compromised.
JWT Authentication
JSON Web Tokens are the dominant authentication mechanism for SaaS APIs. A JWT is a self-contained token that encodes the user's identity and claims, signed with a server-side secret. When a user authenticates, they receive a JWT. On subsequent requests, they present the JWT in the Authorization header. The API verifies the signature without needing to hit the database, which makes JWTs stateless and fast.
Implementation requirements that actually matter:
Algorithm pinning: Only accept tokens signed with your expected algorithm. The "none" algorithm attack — where an attacker crafts a token claiming no signature is required — is still in the wild. Always explicitly specify HS256 or RS256 in your JWT library's verification call. Never trust the algorithm specified in the token header.
Expiry windows: Access tokens should expire in 15 minutes to 1 hour. Refresh tokens can expire in 7-30 days. Short-lived access tokens limit the blast radius of a stolen token. Long-lived tokens are credentials, not tokens.
Storage location: Store access tokens in memory (application state) for single-page applications, not in localStorage. LocalStorage is accessible to any JavaScript on the page, including injected scripts. Store refresh tokens in HttpOnly cookies with SameSite=Strict or SameSite=Lax. An HttpOnly cookie cannot be read by JavaScript — only sent with HTTP requests — which eliminates the primary cross-site scripting theft vector.
Token rotation: Implement refresh token rotation. When a user exchanges a refresh token for a new access token, issue a new refresh token and invalidate the old one. If an attacker steals a refresh token and uses it, the legitimate user's next request with the old token will fail, signaling a compromise.
OAuth 2.0 for Third-Party Access
OAuth 2.0 is the standard for delegated authorization — allowing your users to grant third-party applications access to their data in your SaaS. If your product has an API that partners or customers will use programmatically, or if you offer a "Sign in with Google/GitHub" flow, you are working with OAuth 2.0.
The critical implementation detail is the grant type selection:
- Authorization Code + PKCE: The correct flow for user-facing applications (web apps, mobile apps). PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks and is mandatory for public clients.
- Client Credentials: For machine-to-machine API access where no user is involved. A partner service calling your API to sync data uses client credentials.
- Implicit Grant: Do not use this. It was deprecated in RFC 9700 and is vulnerable to token leakage.
For most startups, implementing a full OAuth 2.0 server is unnecessary overhead. Use a managed identity provider — Auth0, Clerk, Supabase Auth, or AWS Cognito — to handle the OAuth flows. These services absorb the security complexity of token issuance, storage, and rotation. The cost ($0-100/month for most startup-scale user counts) is significantly less than the engineering cost of implementing and maintaining a secure auth server.
Rate Limiting: Protecting Your API From Abuse
An API without rate limiting is an open invitation to abuse. Unauthenticated endpoints without rate limits can be used for credential stuffing, enumeration attacks, and denial-of-service. Even authenticated endpoints need rate limits to prevent excessive scraping and cost exploitation.
Implementation Levels
Gateway-level rate limiting: The first line of defense. Cloudflare, AWS API Gateway, and Kong all support rate limiting at the ingress layer before requests reach your application code. Configure limits by IP address for unauthenticated endpoints and by API key or user ID for authenticated endpoints.
Application-level rate limiting: For fine-grained control — different limits per endpoint, per user tier, or per resource type — implement rate limiting in your application. The standard approach is a sliding window algorithm using Redis:
- Store a counter in Redis with the key
rate_limit:{user_id}:{endpoint}:{window} - Increment the counter on each request using Redis
INCRwith an expiry matching your window - Return HTTP 429 (Too Many Requests) with a
Retry-Afterheader when the limit is exceeded
Recommended limits by endpoint type:
- Authentication endpoints (login, forgot password): 5-10 requests per 15 minutes per IP
- API endpoints for authenticated users: 100-1,000 requests per minute per user depending on tier
- Webhook registration or data export endpoints: 10-30 requests per hour
- Admin or privileged endpoints: 10-20 requests per minute per user
Communicating Limits to API Consumers
Include rate limit information in response headers on every API response:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1741526400
Well-behaved API clients use these headers to back off gracefully rather than hammering until they hit the wall. This is a small implementation effort that significantly reduces support requests from developers integrating with your API.
Input Validation: Never Trust Client Data
Every piece of data your API receives from the outside world must be validated before it touches your database or business logic. This applies to query parameters, request bodies, headers, and file uploads.
SQL Injection
Despite being one of the oldest vulnerability classes, SQL injection consistently appears in the OWASP Top 10 because developers keep writing raw SQL queries with string interpolation. The fix is simple: use parameterized queries or a query builder exclusively. Never construct SQL strings by concatenating user input.
Most ORMs (Sequelize, SQLAlchemy, ActiveRecord, Prisma) use parameterized queries by default. The risk appears when developers bypass the ORM for "performance reasons" using raw queries — always use the parameterized query interface even for raw SQL.
Schema Validation
Use a validation library to enforce the shape, type, and constraints of every incoming request before your business logic runs. In Node.js, Zod and Joi are the standard options. In Python, Pydantic. In Go, the validator package.
Define a schema for every API endpoint that specifies:
- Required vs. optional fields
- Data types (string, number, boolean, array)
- String format constraints (email, UUID, URL, ISO date)
- Length limits (maximum string length, array size)
- Numeric ranges (minimum/maximum values)
Reject requests that fail validation immediately with a 400 (Bad Request) response and a descriptive error message. Do not let malformed data reach your business logic or database.
File Upload Security
File uploads are one of the most commonly exploited attack vectors in SaaS applications. Enforce these controls on every upload endpoint:
- Validate file type by content (MIME type detection), not by file extension. Extensions are trivially spoofable.
- Enforce maximum file size limits (never let an attacker upload a 10 GB file to exhaust your storage or memory)
- Rename uploaded files to a UUID before storage (never preserve user-supplied filenames in the storage path)
- Store uploaded files in cloud storage (S3, GCS), not on your application server's filesystem
- Scan uploaded files for malware using a service like ClamAV or AWS GuardDuty for Malware Protection before making them accessible to other users
CORS Configuration: Limiting Who Can Call Your API
Cross-Origin Resource Sharing (CORS) defines which external domains can make requests to your API from a browser. A permissive Access-Control-Allow-Origin: * allows any website to make cross-origin requests to your API using a logged-in user's credentials — enabling cross-site request forgery in some configurations.
The correct CORS configuration:
Access-Control-Allow-Origin: Specify explicit allowed origins (your frontend domain). Never use*for endpoints that accept authenticated requests.Access-Control-Allow-Methods: List only the HTTP methods your API uses. If an endpoint only supports GET and POST, do not allow PUT or DELETE.Access-Control-Allow-Headers: Specify the headers your API needs.Authorization,Content-Type, and any custom headers your application uses.Access-Control-Allow-Credentials: trueonly when your API needs to accept cookies from cross-origin requests (and only with a specificAccess-Control-Allow-Origin, never with*)
Maintain an environment-specific allowlist. In development, allow localhost:3000. In staging, allow your staging frontend domain. In production, allow only your production frontend domain.
HTTPS and TLS: The Non-Negotiable Baseline
Every API you expose to the public internet must be served over HTTPS. HTTP transmits data in plaintext, meaning any network observer between the client and server — including a hotel Wi-Fi operator, a mobile carrier, or an attacker performing a man-in-the-middle attack — can read and modify requests.
TLS configuration requirements:
- Minimum TLS 1.2. Disable TLS 1.0 and 1.1, which have known vulnerabilities.
- Use TLS 1.3 where possible. It removes deprecated cipher suites and adds improved handshake performance.
- Use strong cipher suites. Disable RC4, 3DES, and export-grade ciphers.
- Redirect all HTTP traffic to HTTPS at the load balancer or CDN layer with a 301 redirect.
- Implement HSTS (HTTP Strict Transport Security) with a minimum
max-ageof 1 year:Strict-Transport-Security: max-age=31536000; includeSubDomains
Certificate management: Use Let's Encrypt for automatic, free TLS certificates. AWS Certificate Manager and GCP Certificate Manager provide managed certificates with automatic renewal. There is no legitimate reason to pay for TLS certificates or to run them manually on a startup budget.
API Key Management
For SaaS products that offer programmatic access, API key management is a security-critical component. Poorly managed API keys are one of the most common sources of credential leaks.
Key generation: Generate API keys using a cryptographically secure random number generator with at least 256 bits of entropy. A UUID is not sufficient — use crypto.randomBytes(32).toString('hex') in Node.js or secrets.token_hex(32) in Python.
Key storage: Never store API keys in plaintext. Hash them using SHA-256 before storing in the database, exactly as you would hash a password. Display the key once at generation time and never again. The user is responsible for saving it.
Key scoping: Allow users to create keys with limited scope — "read-only" keys that cannot modify data, keys restricted to specific API endpoints, keys with an expiration date. Least-privilege keys limit the blast radius of a leaked key.
Key rotation: Provide a self-service key rotation mechanism. When a key is compromised (appeared in a public repository, leaked in a log), the user should be able to revoke the old key and generate a new one without contacting support.
Detecting leaked keys: GitHub's secret scanning feature automatically detects common API key formats committed to public repositories. Register your key format as a custom pattern and configure GitHub to notify you (or revoke the key automatically) when it is found. This is free and catches a significant percentage of accidental key leaks.
OWASP API Security Top 10: The Framework for Your Security Review
The OWASP API Security Top 10 is the most widely referenced framework for API security vulnerabilities. Every startup should run through this list as a security review checklist before launch.
The ten categories and their startup-relevant mitigations:
API1 - Broken Object Level Authorization (BOLA): Verify that every data-access operation checks that the authenticated user owns or has permission to access the specific object being requested. The classic example: GET /api/invoices/1234 should return a 403 if the authenticated user is not the owner of invoice 1234.
API2 - Broken Authentication: Implement short-lived tokens, secure token storage, account lockout after failed attempts, and MFA for sensitive operations.
API3 - Broken Object Property Level Authorization: When returning objects, strip properties the user should not see. Do not return hashedPassword, internalNotes, or other fields just because they exist on the database model.
API4 - Unrestricted Resource Consumption: Implement rate limiting and request size limits. An attacker running millions of requests against your API should be stopped at the rate limiter, not after they exhaust your infrastructure budget.
API5 - Broken Function Level Authorization: Verify that regular users cannot call admin-only endpoints. Authorization checks must be on every endpoint, not just on the frontend navigation.
API6 - Unrestricted Access to Sensitive Business Flows: Protect critical business flows (account creation, payment processing, bulk data export) with rate limiting and bot detection independent of your standard API rate limits.
API7 - Server-Side Request Forgery (SSRF): If your API accepts URLs as input and makes server-side HTTP requests to them, validate and restrict the allowed URL patterns. An attacker can use an SSRF vulnerability to scan your internal network or access cloud metadata endpoints.
API8 - Security Misconfiguration: Disable debug endpoints in production. Do not expose stack traces in API error responses. Remove default credentials from all services. Enforce CORS as described above.
API9 - Improper Inventory Management: Maintain an inventory of every API endpoint you expose, including versioned and deprecated endpoints. Old, forgotten API versions without security updates are a common attack vector.
API10 - Unsafe Consumption of APIs: When your API consumes external APIs, validate the responses with the same rigor you apply to user input. A compromised upstream service can deliver malicious payloads through a trusted integration.
Logging and Monitoring for Security
Security monitoring is not optional for production SaaS. You need to know when attacks are happening, when authentication is failing abnormally, and when sensitive data operations are occurring outside expected patterns.
What to log for every API request:
- Timestamp
- Request method and path (not query parameters for sensitive endpoints)
- Authenticated user ID (if applicable)
- Response status code
- Request duration
- Client IP address
- User agent
Do not log: Passwords, API keys, JWT tokens, session IDs, or any personally identifiable information in request parameters. Log IDs and reference the data, not the data itself.
Alerting rules that catch real attacks:
- More than 10 failed authentication attempts for a single user in 5 minutes (credential stuffing)
- Authentication success from a new country for an account that has never logged in from that region
- More than 100 4xx responses from a single IP in 1 minute (scanning)
- Access to administrative endpoints from non-admin user IDs (authorization bypass attempt)
Penetration Testing: When and How
Penetration testing — having a security professional attempt to break into your application — is the definitive validation that your security implementation works. For startups, the question is when it becomes necessary and cost-effective.
For most startups, the practical answer: Run a basic automated scan (OWASP ZAP, Burp Suite Community Edition) before launch. This catches the obvious issues — open debug endpoints, missing CORS configuration, exposed server headers — without the cost of a manual engagement.
Commission a professional penetration test before enterprise sales or when your compliance requirements (SOC 2, ISO 27001, HIPAA) mandate it. A professional pentest for a SaaS API typically costs $5,000-25,000 depending on scope. Most pre-Series A startups are not yet at the stage where this is necessary unless their target market requires it.
P2C's security engineering practice — informed by ISO 27001:2022 certified processes — includes security architecture review, threat modeling, and integration of DAST (Dynamic Application Security Testing) tools into CI/CD pipelines as part of standard MVP delivery.
Conclusion
API security is not a feature you add. It is a property of how you build. Authentication, rate limiting, input validation, and access control are engineering fundamentals that belong in your first sprint, alongside user management and core product functionality.
The startups that get this right are not paranoid or overly cautious — they are founder-led teams that understand that a single security incident in the first year, when investor relationships are fragile and customer trust is new, can be company-ending. The cost of doing it right is a few extra days of engineering time. The cost of doing it wrong is higher than most founders want to calculate.
P2C builds production-ready, security-first SaaS products. Every MVP we deliver includes the API security foundation described in this guide — because your first 100 users deserve the same protection as your first 100,000.
FAQ
Should I build my own auth system or use Auth0/Clerk? Use a managed identity provider for your MVP. Building a secure authentication system — with token rotation, MFA, session management, and account recovery — is a significant engineering investment with no product differentiation value. Auth0 and Clerk are production-ready, well-audited, and cost $0-100/month for startup user counts. Build the product, not the auth infrastructure.
How do I know if my API is vulnerable to BOLA attacks? Review every endpoint that accepts an object ID as a parameter. For each one, confirm that your code explicitly checks whether the authenticated user has permission to access that specific object. If the only authorization check is "is the user logged in" rather than "does this user own this object," you have a BOLA vulnerability.
What is the most common security mistake early-stage SaaS teams make? Storing sensitive data in logs. Debug-mode logging that captures request bodies — including passwords, tokens, and PII — ends up in log aggregation services that are accessible to the entire engineering team. Define a logging policy on day one that explicitly lists what must never appear in logs.
Do I need security scanning in my CI/CD pipeline? Yes, and it is easier than most teams expect. Trivy (container image scanning), Snyk (dependency vulnerability scanning), and OWASP ZAP (dynamic API scanning) all have GitHub Actions integrations that run automatically on every pull request. The combined setup takes about half a day and catches a class of vulnerabilities that manual review consistently misses.
How does ISO 27001:2022 certification affect my startup's security practices? ISO 27001:2022 provides a structured framework for information security management — policies, risk assessment, access control, incident response, and supplier management. Working with an ISO 27001:2022 certified development partner like P2C means your SaaS product is built within a formal security management system, which supports your own compliance roadmap and provides evidence of security diligence for enterprise customers and investors.


