RESTful API Security Guide: Authentication, Authorization & Best Practices
REST API security protects endpoints through authentication, authorization, encryption, and rate limiting — preventing unauthorized access at every layer.
What You’ll Learn
- Authentication methods: API keys, JWT, OAuth 2.0
- Authorization patterns: RBAC and scope-based access
- HTTPS, TLS, and transport layer security
- Rate limiting, input validation, and CORS
- Security headers and audit logging
Why REST Security Matters
Exposing an API without security is like leaving your front door unlocked with a sign saying “come in.” Every public API is constantly scanned by bots looking for vulnerabilities. DodaTech’s Durga Antivirus Pro API handles sensitive threat data and user information — a breach would expose millions of users’ security status. That’s why every endpoint requires authentication, requests are rate-limited, and all traffic is encrypted with TLS 1.3.
flowchart LR
subgraph "Security Layers"
A["HTTPS/TLS\nEncryption"]
B["Authentication\nWho are you?"]
C["Authorization\nWhat can you do?"]
D["Rate Limiting\nHow many?"]
E["Input Validation\nIs data clean?"]
end
A --> B --> C --> D --> E
style A fill:#dbeafe,stroke:#2563eb
style B fill:#fef3c7,stroke:#d97706
style C fill:#fef3c7,stroke:#d97706
style D fill:#fef3c7,stroke:#d97706
style E fill:#dcfce7,stroke:#16a34a
Authentication vs Authorization
These two terms are often confused. Let’s clarify:
- Authentication = “Who are you?” — verifying identity (login, API key, JWT)
- Authorization = “What can you do?” — checking permissions (admin, read-only, etc.)
Think of a nightclub: authentication is showing your ID at the door. Authorization is the VIP wristband that lets you access the VIP lounge.
HTTPS and TLS
Everything starts with HTTPS. Without encryption, credentials and data travel in plain text.
// ❌ Insecure — credentials visible to anyone on the network
GET http://api.durga-antivirus.com/v1/threats
Authorization: Bearer my-super-secret-token
// ✅ Secure — everything is encrypted
GET https://api.durga-antivirus.com/v1/threats
Authorization: Bearer my-super-secret-tokenWhy HTTPS first: HTTPS encrypts the entire request — headers, body, and query parameters. An attacker on the same Wi-Fi network cannot read your JWT token, API key, or response data. Always enforce HTTPS at the infrastructure level (load balancer, API gateway) before any code runs.
API Keys
The simplest authentication method — a unique key identifies the client:
GET /api/v1/threats?api_key=abc123def456 HTTP/1.1
// Better: use a header
GET /api/v1/threats HTTP/1.1
X-API-Key: abc123def456Pros: Simple, fast, easy to generate and revoke. Cons: No identity granularity — everyone with the same key has the same permissions. Vulnerable to leaking (keys in URLs, logs, source code).
JWT (JSON Web Tokens)
JWT is the most common authentication method for REST APIs. A JWT contains encoded JSON data signed by the server.
POST /auth/login HTTP/1.1
Content-Type: application/json
{"username": "admin", "password": "securepass123"}
---
HTTP/1.1 200 OK
{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbWluIiwicm9sZSI6ImFkbWluIn0.sflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}The client includes this token in every subsequent request:
GET /api/v1/threats HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...Why JWT is stateless: The server doesn’t store the token. It verifies the signature, decodes the payload (user ID, role, expiration), and processes the request. This aligns perfectly with REST’s stateless constraint.
// Verifying a JWT — no session lookup needed
const jwt = require('jsonwebtoken');
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'No token' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // { sub, name, role, iat, exp }
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}Authorization with RBAC
Role-Based Access Control assigns permissions based on roles:
function authorize(...allowedRoles) {
return (req, res, next) => {
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
// Usage
app.get('/api/v1/admin/users', authenticate, authorize('admin'), handler);
app.get('/api/v1/threats', authenticate, authorize('admin', 'analyst', 'readonly'), handler);Rate Limiting
Rate limiting prevents abuse by restricting how many requests a client can make in a time window:
// Simple in-memory rate limiter
const rateLimit = new Map();
function rateLimitMiddleware(req, res, next) {
const key = req.ip || req.headers['x-forwarded-for'];
const now = Date.now();
const windowMs = 60000; // 1 minute
const maxRequests = 100;
if (!rateLimit.has(key)) {
rateLimit.set(key, []);
}
const timestamps = rateLimit.get(key).filter(t => now - t < windowMs);
timestamps.push(now);
rateLimit.set(key, timestamps);
if (timestamps.length > maxRequests) {
return res.status(429).json({
error: { code: 'RATE_LIMIT', message: 'Too many requests' }
});
}
next();
}Common Mistakes
1. Sending API Keys in URLs
GET /api/data?api_key=secret — keys in URLs appear in server logs, browser history, and referrer headers. Always use the Authorization header or X-API-Key header.
2. Not Validating Input
eval() on user input, $where in MongoDB, raw SQL interpolation — these lead to injection attacks. Always validate and sanitize all input. Use parameterized queries for databases.
3. Exposing Too Much in Error Messages
❌ "Database error: Connection failed to mysql://root:password@localhost:3306"
✅ "Internal server error. Request ID: req-abc-123"Error messages should be helpful to developers but never expose internal system details.
4. Ignoring CORS
Without CORS headers, browsers block frontend apps from calling your API:
Access-Control-Allow-Origin: https://dashboard.durga-antivirus.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type5. Not Protecting Against Brute Force
Without rate limiting on authentication endpoints, attackers can try millions of passwords. Add rate limiting specifically on /auth/login with lower thresholds (5 attempts per minute).
6. Disabling HTTPS in Development and Forgetting in Production
APIs deployed without HTTPS expose user data in transit. Use Let’s Encrypt for free TLS certificates and enforce HTTPS with HSTS headers.
Practice Questions
- What is the difference between authentication and authorization?
- Why is JWT preferred over server-side sessions for REST APIs?
- What security problem does HTTPS solve?
- Why should API keys never be sent in URLs?
- What is the purpose of the
403 Forbiddenstatus code?
Answers:
- Authentication verifies identity (“who are you?”). Authorization determines permissions (“what can you do?”).
- JWT is stateless — the token contains all user information, verified by signature. No server-side storage needed, enabling horizontal scaling.
- HTTPS encrypts all data in transit using TLS, preventing eavesdropping, tampering, and man-in-the-middle attacks on the network.
- API keys in URLs appear in server logs, browser history, referrer headers, and can be leaked through caching layers.
403 Forbiddenindicates the client is authenticated but lacks permission to access the resource.
Challenge: Design an authentication and authorization system for Durga Antivirus Pro’s API with three user roles: admin (full access), analyst (view threats, submit samples), and customer (view own devices only). Show the JWT payload structure and middleware pseudocode.
FAQ
Try It Yourself
Generate and verify a JWT using Node.js:
const jwt = require('jsonwebtoken');
// Generate a token
const payload = { sub: 'user-123', name: 'SecurityAnalyst', role: 'analyst' };
const secret = 'your-256-bit-secret';
const token = jwt.sign(payload, secret, { expiresIn: '1h' });
console.log('Token:', token);
// Verify the token
try {
const decoded = jwt.verify(token, secret);
console.log('Verified:', decoded);
} catch (err) {
console.error('Invalid token');
}Run this and notice how the token contains all user information. No database lookup needed to verify — that’s stateless authentication.
What’s Next
| Topic | Description |
|---|---|
| RESTful APIs Overview | Review all REST constraints together |
| Firebase vs Custom Auth | Compare DIY auth with Firebase Authentication |
| GraphQL Security | Security considerations in GraphQL APIs |
| HTTP Security Headers | Security headers like CSP, HSTS, X-Frame-Options |
What’s Next
Congratulations on completing this Restful Security tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro