← Back to blog

API Security in Practice: Authentication, Authorization & Common Attack Prevention

API security is not "just add a token." This article covers authentication models (JWT vs Session), OAuth 2.0 authorization flows, and defense strategies for common attacks including SQL injection, XSS, CSRF, and rate limiting — for backend developers and architects building or reviewing API security.

The Bottom Line: API Security Is Not “Just Add a Token”

Many teams invest only in “add a token” during early API development, then retrofit security after a data breach, API abuse, or malicious scraping incident. But security is not a patch — it is a structural concern that should be considered at the design stage.

This article covers three layers: authentication and authorization, common attack prevention, and a security configuration checklist.


1. Authentication and Authorization

1.1 Authentication Method Selection

MethodProsConsBest For
JWTStateless, cross-service, no storage neededCannot revoke, payload sizeMicroservices, external APIs
SessionServer-side logout, full controlCentral storage neededMonolith, admin systems
API KeySimple, machine-to-machineCoarse-grainedThird-party integrations

Recommended practice: Use JWT with short expiration (15-60 min) + Refresh Token for external APIs. Use Session + Redis for internal admin systems.

1.2 OAuth 2.0 Authorization Flows

OAuth 2.0 is the standard for authorizing third-party access to user data. Four flows for different scenarios:

Authorization Code + PKCE  → Third-party apps accessing user data (most common)
Client Credentials         → Service-to-service communication (no user authorization)
Resource Owner Password    → First-party app login (not recommended unless highly trusted)
Implicit                   → Deprecated, use PKCE instead

For most scenarios, Authorization Code + PKCE is sufficient.

1.3 Permission Model

Use RBAC (Role-Based Access Control) for API-level authorization:

{
  "userId": 1,
  "roles": ["admin", "editor"],
  "permissions": ["post:create", "post:edit", "user:delete"]
}

Middleware checks permissions on each protected endpoint:

function requirePermission(perm: string) {
  return (req, res, next) => {
    if (!req.user.permissions.includes(perm)) {
      return res.status(403).json({ error: 'forbidden' });
    }
    next();
  };
}

2. Common Attacks and Defense

2.1 SQL Injection

ORM frameworks have reduced prevalence, but SQL injection still exists in ORDER BY clauses, dynamic table names, and LIKE queries.

Defense: Always use parameterized queries, never concatenate SQL strings.

// ❌ Wrong
const sql = `SELECT * FROM users WHERE name = '${name}'`;

// ✅ Correct
const sql = 'SELECT * FROM users WHERE name = $1';

2.2 XSS (Cross-Site Scripting)

When an API returns user-generated content (comments, profiles), unescaped content can inject scripts.

Defense: HTML-escape user content before returning it, or ensure Content-Type: application/json prevents the browser from parsing the response as HTML.

2.3 CSRF (Cross-Site Request Forgery)

An attacker诱导s a logged-in user to visit a malicious link, exploiting the user’s session to perform unintended operations.

Defense: Use SameSite Cookie attribute (SameSite=Strict or SameSite=Lax), or require a CSRF Token on every write operation.

2.4 Rate Limiting

An API without rate limiting is an open invitation for abuse.

Layered rate limiting strategy:

Gateway: Global IP-based limit          → 100 req/min/IP
Application: Per-user granular limit    → 10 req/min/user (write operations)
Critical endpoints: Login/register      → 5 req/min/IP

Sliding window counter with Redis:

async function rateLimit(key: string, limit: number, window: number): Promise<boolean> {
  const current = await redis.incr(key);
  if (current === 1) await redis.expire(key, window);
  return current <= limit;
}

2.5 HTTPS

Every production API must enforce HTTPS. Reject HTTP at the code level:

if (req.headers['x-forwarded-proto'] !== 'https') {
  return res.redirect(301, `https://${req.headers.host}${req.url}`);
}

3. Security Configuration Checklist

CategoryItemDescription
TransportHTTPS enforcement301 redirect + HSTS header
AuthenticationToken expirationJWT expiry ≤ 60 minutes
AuthorizationPer-endpoint checkVerify permissions on every endpoint
InputParameterized queriesNo SQL concatenation
OutputHTML escapingEscape user content before returning
RequestRate limitingLayered (gateway + app + critical)
RequestCORS whitelistOnly trusted domains
ResponseSecurity headersX-Frame-Options, X-Content-Type-Options, Referrer-Policy

API security is not a one-time investment — every new endpoint and every dependency upgrade is an opportunity to review your security posture. A security checklist in Code Review and CI is far cheaper than fixing a breach post-incident.

Need backend API development or security auditing? Contact us — tell us your interface scope and scale, feasibility within 24 hours.

FAQ

JWT or Session authentication — which should I choose?

JWT is stateless and works well across services (e.g., passing identity between microservices), but you cannot actively revoke it, and leaked tokens cannot be invalidated. Session-based auth allows server-side logout and full control, but requires a central storage layer (Redis/DB). Recommendation: use JWT with short expiration (15-60 min) for external APIs, and Session for internal admin systems.

Do I need HTTPS for my API?

Yes. HTTPS encrypts传输 content to prevent man-in-the-middle attacks, provides server identity verification, and ensures data integrity. Without HTTPS, tokens and passwords are transmitted in plain text and visible to anyone sniffing the network. Every production API should enforce HTTPS and reject HTTP requests at the code level.

Is SQL injection still a real threat?

Yes. While ORM frameworks have reduced its prevalence, SQL injection still exists wherever raw SQL concatenation is used — especially in ORDER BY clauses, dynamic table names, and LIKE queries. The defense is simple: never concatenate SQL strings. Always use parameterized queries or prepared statements.

How should API rate limiting be implemented?

Layered rate limiting: ① Gateway-level — global limits by IP and API Key (e.g., 100 req/min per IP); ② Application-level — finer limits by user ID (e.g., 10 write operations/min per user); ③ Critical endpoints — targeted limits (e.g., 5 login attempts/min per IP). Use Redis INCR + EXPIRE for sliding window counters, or Nginx limit_req for simple throttling.

This article comes from AI Enable Harness front-line delivery practice. Need a similar system or optimization service?

Subscribe to Updates

Get notified when new articles are published. No spam, occasional updates only.

Subscribe →