# API Authentication & Rate Limiting

This directory contains the authentication middleware and rate limiter for the Multilingual Press Zone REST API.

## Components

### AuthMiddleware.php

Centralized authentication and authorization for REST API endpoints.

#### Features

- **Permission Checks**: Granular permission checks for different operations
  - `canReadLanguages()` - Check if user can read languages
  - `canManageLanguages()` - Check if user can manage languages
  - `canReadTranslations()` - Check if user can read translations
  - `canManageTranslations()` - Check if user can manage translations
  - `canTranslateContent()` - Check if user can translate content

- **Request Verification**: Validates REST API requests
  - `verifyRequest()` - Verify request integrity (WordPress handles nonce automatically)

- **Audit Logging**: Get user information for audit trails
  - `getCurrentUserForAudit()` - Returns user ID, username, IP address, and user agent
  - `getClientIP()` - Handles proxy headers (X-Forwarded-For, X-Real-IP, etc.)

#### Usage Example

```php
use MultilingualPressZone\API\AuthMiddleware;

$auth = new AuthMiddleware();

// Check permissions
if (!$auth->canManageLanguages()) {
    return new WP_Error('forbidden', 'Insufficient permissions', ['status' => 403]);
}

// Get audit info
$audit_info = $auth->getCurrentUserForAudit();
error_log(sprintf(
    'User %s (ID: %d) from IP %s performed action',
    $audit_info['username'],
    $audit_info['user_id'],
    $audit_info['ip_address']
));
```

### RateLimiter.php

Prevents API abuse with rate limiting using WordPress transients.

#### Features

- **Different Limits by User Type**:
  - Anonymous users: 10 requests/minute
  - Authenticated users: 60 requests/minute
  - Admin users: 300 requests/minute

- **Rate Limit Headers**: Adds standard rate limit headers to responses
  - `X-RateLimit-Limit` - Total requests allowed per window
  - `X-RateLimit-Remaining` - Remaining requests in current window
  - `X-RateLimit-Reset` - Unix timestamp when limit resets

- **Error Responses**: Creates proper 429 Too Many Requests responses

- **Manual Reset**: Admin can reset rate limits for testing or override

#### Usage Example

```php
use MultilingualPressZone\API\RateLimiter;

$rate_limiter = new RateLimiter();
$identifier = 'user_' . get_current_user_id();
$user_id = get_current_user_id();

// Check rate limit
if (!$rate_limiter->isAllowed($identifier, $user_id)) {
    return $rate_limiter->createErrorResponse($identifier, $user_id);
}

// Process request...

// Add rate limit headers to response
$response = new WP_REST_Response(['success' => true]);
return $rate_limiter->addHeaders($response, $identifier, $user_id);
```

### LanguagesRestController.php

Example REST controller demonstrating integration with AuthMiddleware and RateLimiter.

#### Endpoints

- `GET /wp-json/multilingual-press-zone/v1/languages` - Get all languages
- `GET /wp-json/multilingual-press-zone/v1/languages/{code}` - Get single language
- `POST /wp-json/multilingual-press-zone/v1/languages` - Create new language

#### Features

- Rate limiting on all endpoints
- Permission checks via AuthMiddleware
- Audit logging for create operations
- Standard rate limit headers on all responses

## Integration Guide

### Step 1: Register REST Controllers

Add REST controller registration to your plugin's initialization:

```php
// In includes/Core/Plugin.php

private function register_rest_routes(): void {
    add_action('rest_api_init', function () {
        // Register Languages REST Controller
        $languages_controller = new \MultilingualPressZone\API\LanguagesRestController(
            $this->language_manager
        );
        $languages_controller->register_routes();

        // Register other controllers...
    });
}
```

Call `register_rest_routes()` in your plugin's `init()` method:

```php
public function init(): void {
    $this->load_dependencies();
    $this->register_hooks();
    $this->register_rest_routes(); // Add this line

    if (is_admin()) {
        $this->init_admin();
    }

    if (!is_admin()) {
        $this->init_frontend();
    }
}
```

### Step 2: Update Existing REST Controllers

Update existing REST controllers (DashboardRestController, JobsRestController) to use rate limiting:

```php
class DashboardRestController extends WP_REST_Controller {
    private RateLimiter $rate_limiter;
    private AuthMiddleware $auth_middleware;

    public function __construct() {
        $this->rate_limiter = new RateLimiter();
        $this->auth_middleware = new AuthMiddleware();
    }

    public function get_stats(WP_REST_Request $request) {
        // Check rate limit
        $identifier = $this->getRequestIdentifier($request);
        $user_id = get_current_user_id();

        if (!$this->rate_limiter->isAllowed($identifier, $user_id ?: null)) {
            return $this->rate_limiter->createErrorResponse($identifier, $user_id ?: null);
        }

        // Process request...

        $response = new WP_REST_Response(['success' => true, 'data' => $stats]);
        return $this->rate_limiter->addHeaders($response, $identifier, $user_id ?: null);
    }

    private function getRequestIdentifier(WP_REST_Request $request): string {
        $user_id = get_current_user_id();
        if ($user_id) {
            return 'user_' . $user_id;
        }

        // Use IP for anonymous requests
        $auth = new \MultilingualPressZone\API\AuthMiddleware();
        $audit_info = $auth->getCurrentUserForAudit();
        return 'ip_' . ($audit_info['ip_address'] ?: 'unknown');
    }
}
```

### Step 3: Test Rate Limiting

Test rate limiting with multiple requests:

```bash
# Test anonymous rate limit (10 requests/minute)
for i in {1..12}; do
  curl -i http://your-site.local/wp-json/multilingual-press-zone/v1/languages
  sleep 1
done

# Test authenticated rate limit (60 requests/minute)
for i in {1..65}; do
  curl -i -H "X-WP-Nonce: YOUR_NONCE" \
    http://your-site.local/wp-json/multilingual-press-zone/v1/languages
  sleep 1
done
```

Check for:
- Rate limit headers in responses
- 429 status code when limit exceeded
- Proper retry_after timestamp

### Step 4: Monitor and Adjust

Monitor rate limit violations:

```php
// Add logging to RateLimiter::isAllowed()
if ($count >= $limit) {
    $audit = new AuthMiddleware();
    $info = $audit->getCurrentUserForAudit();
    error_log(sprintf(
        'MPZ Rate Limit: %s exceeded limit (%d/%d)',
        $identifier,
        $count,
        $limit
    ));
    return false;
}
```

Adjust limits if needed by modifying constants in `RateLimiter.php`:

```php
private const LIMIT_ANONYMOUS = 20;      // Increase to 20
private const LIMIT_AUTHENTICATED = 100; // Increase to 100
private const LIMIT_ADMIN = 500;         // Increase to 500
```

## Security Best Practices

1. **Always use AuthMiddleware** for permission checks in REST controllers
2. **Always apply rate limiting** to prevent API abuse
3. **Log security events** using audit information
4. **Use proper error messages** that don't leak system information
5. **Validate all input** even if you have rate limiting
6. **Monitor rate limit violations** to detect potential attacks

## Testing Checklist

- [ ] Test rate limiting with multiple requests
- [ ] Verify rate limit headers are set correctly
- [ ] Check 429 response when limit exceeded
- [ ] Test different user roles get different limits
- [ ] Verify anonymous users are limited by IP
- [ ] Test authenticated users are limited by user ID
- [ ] Verify admin users have higher limits
- [ ] Test permission checks work correctly
- [ ] Verify audit logging captures correct information
- [ ] Test IP detection handles proxy headers correctly

## Troubleshooting

### Rate Limits Not Working

1. Check if transients are working: `get_transient('test')` / `set_transient('test', 'value', 60)`
2. Verify object cache is configured correctly
3. Check if rate limiter is instantiated in controller
4. Verify `isAllowed()` is called before processing request

### Incorrect Rate Limit Headers

1. Verify `addHeaders()` is called on the response
2. Check if response is WP_REST_Response (not WP_Error)
3. Verify headers are not being stripped by proxy/cache

### Permission Checks Failing

1. Verify user has correct WordPress capabilities
2. Check if `current_user_can()` returns expected value
3. Test with different user roles
4. Verify permission callback is set correctly in route registration

## Performance Considerations

- **Transients**: Rate limiter uses WordPress transients for storage
  - Fast for small numbers of users
  - Consider object cache (Redis/Memcached) for high traffic
  - Transients auto-expire (no cleanup needed)

- **Database Queries**: AuthMiddleware uses `wp_get_current_user()`
  - Cached by WordPress
  - No additional database queries per request

- **Rate Limit Headers**: Added to every response
  - Minimal overhead (< 1ms)
  - No database queries

## Future Enhancements

- [ ] Add rate limit bypass for specific API keys
- [ ] Implement sliding window rate limiting
- [ ] Add Redis backend for high-traffic sites
- [ ] Create admin UI for viewing rate limit violations
- [ ] Add webhook notifications for rate limit violations
- [ ] Implement IP whitelist/blacklist
- [ ] Add rate limit analytics dashboard
