Back to Articles
API Security
Updated Oct 25, 2025

Complete API Security Testing Checklist: Comprehensive Guide

APIs are the backbone of modern applications, but they're also prime targets for cyberattacks. A single vulnerability in your API can lead to data breaches, unauthorized access, and complete system compromise. Here's everything you need to test and secure your APIs against real-world threats.

Understanding API Security Threats

Before diving into testing, it's crucial to understand the threats APIs face:

Common API Attack Vectors

  • Injection Attacks: SQL, NoSQL, LDAP, and command injection
  • Broken Authentication: Weak tokens, session management flaws
  • Broken Authorization: IDOR, privilege escalation, access control bypass
  • Data Exposure: Sensitive data in responses, logs, or error messages
  • Rate Limiting Bypass: DoS attacks, brute force attempts
  • Input Validation: Malicious payloads, oversized requests
  • Business Logic Flaws: Workflow bypass, state manipulation

Comprehensive API Security Testing Framework

1. Authentication and Session Management

Strong Authentication Implementation

// Example: Secure JWT implementation
const jwt = require('jsonwebtoken');

// Generate secure token
function generateAccessToken(user) {
  return jwt.sign(
    { 
      userId: user.id, 
      role: user.role,
      iat: Math.floor(Date.now() / 1000)
    },
    process.env.JWT_SECRET,
    { 
      expiresIn: '15m',
      algorithm: 'HS256',
      issuer: 'your-api',
      audience: 'your-app'
    }
  );
}

// Validate token
function validateToken(token) {
  try {
    return jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256'],
      issuer: 'your-api',
      audience: 'your-app'
    });
  } catch (error) {
    throw new Error('Invalid token');
  }
}

Testing Authentication Security

Test Cases:

  1. Token Validation

    # Test with invalid token
    curl -H "Authorization: Bearer invalid-token" https://api.example.com/users
    
    # Test with expired token
    curl -H "Authorization: Bearer expired-token" https://api.example.com/users
    
    # Test without token
    curl https://api.example.com/users
    
  2. Token Rotation

    // Test token refresh mechanism
    describe('Token Refresh', () => {
      test('should rotate refresh tokens', async () => {
        const response = await request(app)
          .post('/api/auth/refresh')
          .set('Authorization', `Bearer ${validRefreshToken}`);
        
        expect(response.body.accessToken).toBeDefined();
        expect(response.body.refreshToken).toBeDefined();
        expect(response.body.refreshToken).not.toBe(validRefreshToken);
      });
    });
    
  3. Multi-Factor Authentication

    // Test MFA enforcement
    test('should require MFA for sensitive operations', async () => {
      const response = await request(app)
        .post('/api/admin/users')
        .set('Authorization', `Bearer ${userToken}`)
        .send({ email: '[email protected]' });
      
      expect(response.status).toBe(403);
      expect(response.body.error).toContain('MFA required');
    });
    

Session Management Best Practices

  • Use HttpOnly, Secure cookies for session tokens
  • Implement proper session timeout
  • Use secure session storage
  • Implement concurrent session limits
// Secure session configuration
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,
    httpOnly: true,
    maxAge: 15 * 60 * 1000, // 15 minutes
    sameSite: 'strict'
  },
  store: new RedisStore({
    host: 'localhost',
    port: 6379,
    ttl: 900 // 15 minutes
  })
}));

2. Authorization and Access Control

Insecure Direct Object Reference (IDOR) Testing

Test Cases:

# Test IDOR vulnerability
# User A tries to access User B's data
curl -H "Authorization: Bearer user-a-token" https://api.example.com/users/123/orders
curl -H "Authorization: Bearer user-b-token" https://api.example.com/users/123/orders

# Test with different user IDs
curl -H "Authorization: Bearer user-token" https://api.example.com/users/999/orders
curl -H "Authorization: Bearer user-token" https://api.example.com/users/1/orders

Secure Implementation:

// Secure resource access control
app.get('/api/users/:userId/orders', authenticateToken, async (req, res) => {
  const { userId } = req.params;
  const requestingUser = req.user;
  
  // Enforce ownership check
  if (requestingUser.id !== parseInt(userId) && requestingUser.role !== 'admin') {
    return res.status(403).json({ error: 'Access denied' });
  }
  
  const orders = await Order.findByUserId(userId);
  res.json(orders);
});

Role-Based Access Control (RBAC) Testing

// Test role-based access
describe('RBAC Testing', () => {
  test('admin can access all resources', async () => {
    const response = await request(app)
      .get('/api/admin/users')
      .set('Authorization', `Bearer ${adminToken}`);
    
    expect(response.status).toBe(200);
  });
  
  test('user cannot access admin resources', async () => {
    const response = await request(app)
      .get('/api/admin/users')
      .set('Authorization', `Bearer ${userToken}`);
    
    expect(response.status).toBe(403);
  });
});

3. Input Validation and Data Sanitization

Comprehensive Input Validation

// Input validation middleware
const { body, validationResult } = require('express-validator');

const validateUserInput = [
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/),
  body('age').isInt({ min: 0, max: 120 }),
  body('role').isIn(['user', 'admin', 'moderator']),
  (req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    next();
  }
];

SQL Injection Testing

# Test for SQL injection
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "password", "age": "1 OR 1=1"}'

# Test with malicious payloads
curl -X POST https://api.example.com/search \
  -H "Content-Type: application/json" \
  -d '{"query": "test\"; DROP TABLE users; --"}'

NoSQL Injection Testing

# Test for NoSQL injection
curl -X POST https://api.example.com/login \
  -H "Content-Type: application/json" \
  -d '{"email": {"$ne": null}, "password": {"$ne": null}}'

# Test with MongoDB operators
curl -X GET "https://api.example.com/users?filter={\"$where\":\"this.password.length > 0\"}"

4. Rate Limiting and Abuse Prevention

Comprehensive Rate Limiting Implementation

const rateLimit = require('express-rate-limit');
const slowDown = require('express-slow-down');

// General API rate limiting
const generalLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP',
  standardHeaders: true,
  legacyHeaders: false,
});

// Strict rate limiting for auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs
  message: 'Too many authentication attempts',
  skipSuccessfulRequests: true,
});

// Slow down after rate limit
const speedLimiter = slowDown({
  windowMs: 15 * 60 * 1000, // 15 minutes
  delayAfter: 50, // allow 50 requests per 15 minutes, then...
  delayMs: 500 // begin adding 500ms of delay per request above 50
});

app.use('/api/', generalLimiter);
app.use('/api/auth/', authLimiter);
app.use('/api/', speedLimiter);

Rate Limiting Testing

# Test rate limiting
for i in {1..10}; do
  curl -X POST https://api.example.com/auth/login \
    -H "Content-Type: application/json" \
    -d '{"email": "[email protected]", "password": "wrong"}'
done

# Test with different IPs (use proxy or different machines)
curl -X POST https://api.example.com/auth/login \
  -H "X-Forwarded-For: 192.168.1.100" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "wrong"}'

5. Error Handling and Information Disclosure

Secure Error Handling

// Secure error handling middleware
function errorHandler(err, req, res, next) {
  // Log error for debugging
  console.error(err.stack);
  
  // Don't expose internal errors
  if (err.name === 'ValidationError') {
    return res.status(400).json({
      error: 'Validation failed',
      details: err.details
    });
  }
  
  if (err.name === 'UnauthorizedError') {
    return res.status(401).json({
      error: 'Unauthorized'
    });
  }
  
  // Generic error response
  res.status(500).json({
    error: 'Internal server error'
  });
}

Error Handling Testing

# Test error responses
curl -X GET https://api.example.com/users/999999
# Should return generic error, not stack trace

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"invalid": "data"}'
# Should return validation error without internal details

6. Transport Security and Headers

HTTPS Enforcement

// HTTPS enforcement middleware
function enforceHTTPS(req, res, next) {
  if (req.header('x-forwarded-proto') !== 'https' && process.env.NODE_ENV === 'production') {
    return res.redirect(`https://${req.header('host')}${req.url}`);
  }
  next();
}

// Security headers middleware
function securityHeaders(req, res, next) {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
  next();
}

CORS Configuration

// Secure CORS configuration
const corsOptions = {
  origin: function (origin, callback) {
    const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
    if (!origin || allowedOrigins.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  optionsSuccessStatus: 200,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
};

app.use(cors(corsOptions));

7. Business Logic Testing

Workflow Bypass Testing

// Test business logic vulnerabilities
describe('Business Logic Testing', () => {
  test('should not allow negative payments', async () => {
    const response = await request(app)
      .post('/api/payments')
      .set('Authorization', `Bearer ${userToken}`)
      .send({
        amount: -100,
        recipient: '[email protected]'
      });
    
    expect(response.status).toBe(400);
  });
  
  test('should enforce payment limits', async () => {
    const response = await request(app)
      .post('/api/payments')
      .set('Authorization', `Bearer ${userToken}`)
      .send({
        amount: 1000000, // Exceeds daily limit
        recipient: '[email protected]'
      });
    
    expect(response.status).toBe(400);
  });
});

8. API Versioning and Deprecation

Secure API Versioning

// API versioning middleware
function apiVersioning(req, res, next) {
  const version = req.header('API-Version') || 'v1';
  
  if (version === 'v1') {
    req.apiVersion = 'v1';
  } else if (version === 'v2') {
    req.apiVersion = 'v2';
  } else {
    return res.status(400).json({
      error: 'Unsupported API version',
      supportedVersions: ['v1', 'v2']
    });
  }
  
  next();
}

9. Monitoring and Logging

Comprehensive API Logging

// API logging middleware
function apiLogger(req, res, next) {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    const logData = {
      timestamp: new Date().toISOString(),
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      duration: duration,
      userAgent: req.get('User-Agent'),
      ip: req.ip,
      userId: req.user?.id
    };
    
    // Log to secure logging system
    logger.info('API Request', logData);
    
    // Alert on suspicious activity
    if (res.statusCode >= 400 || duration > 5000) {
      alerting.sendAlert('API Issue', logData);
    }
  });
  
  next();
}

10. Automated Security Testing

API Security Test Suite

// Comprehensive API security tests
describe('API Security Tests', () => {
  describe('Authentication', () => {
    test('should reject invalid tokens', async () => {
      const response = await request(app)
        .get('/api/users')
        .set('Authorization', 'Bearer invalid-token');
      
      expect(response.status).toBe(401);
    });
    
    test('should enforce token expiration', async () => {
      const expiredToken = generateExpiredToken();
      const response = await request(app)
        .get('/api/users')
        .set('Authorization', `Bearer ${expiredToken}`);
      
      expect(response.status).toBe(401);
    });
  });
  
  describe('Authorization', () => {
    test('should prevent IDOR attacks', async () => {
      const response = await request(app)
        .get('/api/users/999/orders')
        .set('Authorization', `Bearer ${userToken}`);
      
      expect(response.status).toBe(403);
    });
  });
  
  describe('Input Validation', () => {
    test('should prevent SQL injection', async () => {
      const response = await request(app)
        .post('/api/search')
        .send({ query: "'; DROP TABLE users; --" });
      
      expect(response.status).toBe(400);
    });
  });
});

OWASP API Security Top 10 Alignment

API1: Broken Object Level Authorization

  • Test IDOR on every resource endpoint
  • Verify ownership checks for all operations
  • Test with different user contexts

API2: Broken Authentication

  • Test token validation and expiration
  • Verify secure token generation
  • Test authentication bypass attempts

API3: Broken Object Property Level Authorization

  • Test field-level access controls
  • Verify sensitive field filtering
  • Test property manipulation

API4: Unrestricted Resource Consumption

  • Test rate limiting effectiveness
  • Verify resource quotas
  • Test DoS attack scenarios

API5: Broken Function Level Authorization

  • Test role-based access controls
  • Verify function-level permissions
  • Test privilege escalation

API6: Unrestricted Access to Sensitive Business Flows

  • Test business logic workflows
  • Verify state transitions
  • Test workflow bypass attempts

API7: Server Side Request Forgery (SSRF)

  • Test URL parameter validation
  • Verify internal network access
  • Test metadata endpoint access

API8: Security Misconfiguration

  • Test security headers
  • Verify CORS configuration
  • Test error handling

API9: Improper Inventory Management

  • Test API versioning
  • Verify deprecated endpoint handling
  • Test documentation accuracy

API10: Unsafe Consumption of APIs

  • Test third-party API integration
  • Verify input validation
  • Test error handling

Continuous Security Monitoring

Real-time Security Monitoring

// Security monitoring middleware
function securityMonitoring(req, res, next) {
  // Monitor for suspicious patterns
  const suspiciousPatterns = [
    /union.*select/i,
    /script.*alert/i,
    /\.\.\//,
    /<script/i
  ];
  
  const requestBody = JSON.stringify(req.body);
  const requestQuery = JSON.stringify(req.query);
  
  for (const pattern of suspiciousPatterns) {
    if (pattern.test(requestBody) || pattern.test(requestQuery)) {
      logger.warn('Suspicious request detected', {
        ip: req.ip,
        url: req.url,
        body: req.body,
        query: req.query
      });
      
      // Optionally block the request
      return res.status(400).json({ error: 'Invalid request' });
    }
  }
  
  next();
}

Testing workflow

# Example: probing authz on a REST endpoint
curl -i -H "Authorization: Bearer <token-of-user-A>" https://api.example.com/v1/orders/123

# Then try with a different user token; expect 403 if not owned

GraphQL:

{
  order(id: 123) { id userId total }
}

Ensure resolvers enforce ownership checks, not just schema-level types.

Common pitfalls

  • CORS wide open with credentials
  • Putting secrets in mobile apps or SPA bundles
  • Long‑lived tokens without rotation

Advanced tips

  • Log and alert on authz denials by resource type to discover IDOR attempts
  • Use structured scopes; avoid "god" tokens
  • Threat‑model integrations and webhooks

OWASP API Top 10 alignment (brief)

  • API1: Broken Object Level Authorization (test IDOR on every resource)
  • API2: Broken Authentication (short‑lived tokens, MFA for critical paths)
  • API3: Broken Object Property Level Authorization (reject unknown/extra fields)
  • API4: Unrestricted Resource Consumption (rate limits, timeouts)
  • API5: Broken Function Level Authorization (verify action-level permissions)
  • API6: Unrestricted Access to Sensitive Business Flows (protect important workflows)
  • API7: Server Side Request Forgery (validate outbound calls, allowlists)
  • API8: Security Misconfiguration (disable debug, strict CORS, headers)
  • API9: Improper Inventory Management (document versions, deprecate safely)
  • API10: Unsafe Consumption of APIs (validate third-party data; timeouts/retries)

Pair this with ongoing monitoring from the Web security monitoring guide and deeper testing from the Penetration testing guide.

Conclusion

Work through this checklist regularly and before major releases. Close easy gaps first, then refine limits and scopes.

Run focused checks and watch for regressions in the Barrion dashboard. For a quick look at your public surface, try the Network Security tool.

Frequently asked questions

Q: How do I quickly test for IDOR?

A: Use two accounts. With account A, note a resource ID; with account B, request the same ID. Expect 403 if not owned.

Q: What should my default CORS config be?

A: Avoid *. Set exact origins and avoid credentials unless needed. Treat CORS like a routing control, not an auth feature.

Trusted by IT Professionals

IT professionals worldwide trust Barrion for comprehensive vulnerability detection.
Get detailed security reports with actionable fixes in under 60 seconds.

Barrion logo iconBarrion

Barrion delivers automated security scans and real-time monitoring to keep your applications secure.

Contact Us

Have questions or need assistance? Reach out to our team for support.

© 2025 Barrion - All Rights Reserved.