PHP API authentication security provides comprehensive protection for web APIs using modern authentication methods and security best practices.
PHP API Authentication Security: Complete Guide to Secure API Development with Modern PHP
PHP API authentication security provides comprehensive protection for web APIs using modern authentication methods and security best practices.
API Security
PHP authentication, API security, and modern protection create secure applications.
This guide covers essential security patterns for PHP API development.
Understanding API Authentication
API authentication verifies client identity and authorizes access to resources.
Authentication Basics
API authentication, identity verification, and access control create security.
Proper authentication prevents unauthorized access while enabling legitimate use.
JWT Authentication
Implementing JSON Web Token authentication in PHP APIs.
Token Security
JWT authentication, token security, and web tokens create stateless authentication.
JWT provides secure, scalable authentication for distributed systems.
<?php
// JWT Authentication implementation
class JwtAuth {
private $secretKey;
private $algorithm = 'HS256';
private $expiresIn = 3600; // 1 hour
public function __construct(string $secretKey) {
$this->secretKey = $secretKey;
}
public function generateToken(array $payload): string {
$header = [
'typ' => 'JWT',
'alg' => $this->algorithm
];
$payload['iat'] = time();
$payload['exp'] = time() + $this->expiresIn;
$headerEncoded = $this->base64UrlEncode(json_encode($header));
$payloadEncoded = $this->base64UrlEncode(json_encode($payload));
$signature = hash_hmac(
'sha256',
"$headerEncoded.$payloadEncoded",
$this->secretKey,
true
);
$signatureEncoded = $this->base64UrlEncode($signature);
return "$headerEncoded.$payloadEncoded.$signatureEncoded";
}
public function verifyToken(string $token): ?array {
$parts = explode('.', $token);
if (count($parts) !== 3) {
return null;
}
[$headerEncoded, $payloadEncoded, $signatureEncoded] = $parts;
$signature = hash_hmac(
'sha256',
"$headerEncoded.$payloadEncoded",
$this->secretKey,
true
);
if ($this->base64UrlEncode($signature) !== $signatureEncoded) {
return null;
}
$payload = json_decode($this->base64UrlDecode($payloadEncoded), true);
if ($payload['exp'] < time()) {
return null;
}
return $payload;
}
private function base64UrlEncode(string $data): string {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
private function base64UrlDecode(string $data): string {
return base64_decode(strtr($data, '-_', '+/'));
}
}
OAuth2 Implementation
Building OAuth2 authorization server and client applications.
OAuth2 Security
OAuth2 implementation, authorization server, and client applications create standards.
OAuth2 provides secure delegated authorization for third-party access.
<?php
// OAuth2 Authorization Server
class OAuth2Server {
private $clientRepository;
private $accessTokenRepository;
private $userRepository;
public function __construct(
ClientRepository $clientRepository,
AccessTokenRepository $accessTokenRepository,
UserRepository $userRepository
) {
$this->clientRepository = $clientRepository;
$this->accessTokenRepository = $accessTokenRepository;
$this->userRepository = $userRepository;
}
public function authorize(array $request): array {
$clientId = $request['client_id'] ?? null;
$redirectUri = $request['redirect_uri'] ?? null;
$scopes = $request['scope'] ?? 'read';
$state = $request['state'] ?? null;
// Validate client
$client = $this->clientRepository->findById($clientId);
if (!$client || $client->redirect_uri !== $redirectUri) {
throw new OAuth2Exception('Invalid client');
}
// Generate authorization code
$authCode = $this->generateAuthorizationCode();
// Store authorization code
$this->storeAuthorizationCode($authCode, $clientId, $scopes, $state);
return [
'authorization_code' => $authCode,
'redirect_uri' => $redirectUri . '?code=' . $authCode . '&state=' . $state
];
}
public function token(array $request): array {
$grantType = $request['grant_type'] ?? null;
switch ($grantType) {
case 'authorization_code':
return $this->handleAuthorizationCodeGrant($request);
case 'client_credentials':
return $this->handleClientCredentialsGrant($request);
case 'refresh_token':
return $this->handleRefreshTokenGrant($request);
default:
throw new OAuth2Exception('Unsupported grant type');
}
}
private function handleAuthorizationCodeGrant(array $request): array {
$code = $request['code'] ?? null;
$clientId = $request['client_id'] ?? null;
$clientSecret = $request['client_secret'] ?? null;
// Verify client credentials
$client = $this->clientRepository->findById($clientId);
if (!$client || !$this->verifyClientSecret($client, $clientSecret)) {
throw new OAuth2Exception('Invalid client credentials');
}
// Verify authorization code
$authData = $this->getAuthorizationCodeData($code);
if (!$authData || $authData['client_id'] !== $clientId) {
throw new OAuth2Exception('Invalid authorization code');
}
// Generate access token
$accessToken = $this->generateAccessToken($authData['user_id'], $authData['scopes']);
$refreshToken = $this->generateRefreshToken($authData['user_id']);
// Store tokens
$this->accessTokenRepository->store($accessToken, $authData['user_id'], $authData['scopes']);
// Remove authorization code
$this->removeAuthorizationCode($code);
return [
'access_token' => $accessToken,
'token_type' => 'Bearer',
'expires_in' => 3600,
'refresh_token' => $refreshToken,
'scope' => $authData['scopes']
];
}
}
API Key Authentication
Implementing API key-based authentication for simple scenarios.
Key Security
API keys, key authentication, and simple security create basic protection.
API keys provide straightforward authentication for machine-to-machine communication.
<?php
// API Key Authentication
class ApiKeyAuth {
private $apiKeyRepository;
public function __construct(ApiKeyRepository $apiKeyRepository) {
$this->apiKeyRepository = $apiKeyRepository;
}
public function authenticate(Request $request): ?User {
$apiKey = $this->extractApiKey($request);
if (!$apiKey) {
return null;
}
$keyData = $this->apiKeyRepository->findByKey($apiKey);
if (!$keyData || !$keyData->isActive()) {
return null;
}
// Update last used timestamp
$this->apiKeyRepository->updateLastUsed($apiKey);
return $keyData->getUser();
}
private function extractApiKey(Request $request): ?string {
// Check header
$headerKey = $request->getHeader('X-API-Key');
if ($headerKey) {
return $headerKey;
}
// Check query parameter
$queryKey = $request->getQuery('api_key');
if ($queryKey) {
return $queryKey;
}
return null;
}
public function generateApiKey(User $user, array $scopes = []): string {
$apiKey = $this->generateRandomKey();
$keyData = new ApiKey([
'key' => $apiKey,
'user_id' => $user->getId(),
'scopes' => $scopes,
'created_at' => new DateTime(),
'last_used_at' => null,
'is_active' => true
]);
$this->apiKeyRepository->store($keyData);
return $apiKey;
}
private function generateRandomKey(): string {
return bin2hex(random_bytes(32));
}
}
Rate Limiting
Implementing rate limiting to prevent API abuse.
Rate Protection
Rate limiting, API abuse prevention, and usage control create stability.
Rate limiting protects APIs from abuse while ensuring fair usage.
<?php
// Rate Limiting Implementation
class RateLimiter {
private $redis;
private $config;
public function __construct(Redis $redis, array $config) {
$this->redis = $redis;
$this->config = $config;
}
public function checkLimit(string $identifier, string $route = 'default'): bool {
$key = "rate_limit:{$route}:{$identifier}";
$limit = $this->config[$route]['requests'] ?? 100;
$window = $this->config[$route]['window'] ?? 3600;
$current = $this->redis->incr($key);
if ($current === 1) {
$this->redis->expire($key, $window);
}
if ($current > $limit) {
return false;
}
return true;
}
public function getRemainingRequests(string $identifier, string $route = 'default'): int {
$key = "rate_limit:{$route}:{$identifier}";
$limit = $this->config[$route]['requests'] ?? 100;
$current = $this->redis->get($key) ?? 0;
return max(0, $limit - (int)$current);
}
public function getResetTime(string $identifier, string $route = 'default'): int {
$key = "rate_limit:{$route}:{$identifier}";
return $this->redis->ttl($key);
}
}
// Rate Limiting Middleware
class RateLimitMiddleware {
private $rateLimiter;
public function __construct(RateLimiter $rateLimiter) {
$this->rateLimiter = $rateLimiter;
}
public function handle(Request $request, callable $next): Response {
$identifier = $this->getIdentifier($request);
$route = $this->getRoute($request);
if (!$this->rateLimiter->checkLimit($identifier, $route)) {
return new Response('Rate limit exceeded', 429, [
'X-RateLimit-Limit' => $this->rateLimiter->getLimit($route),
'X-RateLimit-Remaining' => 0,
'X-RateLimit-Reset' => $this->rateLimiter->getResetTime($identifier, $route)
]);
}
$response = $next($request);
$response->withHeaders([
'X-RateLimit-Limit' => $this->rateLimiter->getLimit($route),
'X-RateLimit-Remaining' => $this->rateLimiter->getRemainingRequests($identifier, $route),
'X-RateLimit-Reset' => $this->rateLimiter->getResetTime($identifier, $route)
]);
return $response;
}
private function getIdentifier(Request $request): string {
// Use IP address for unauthenticated requests
// Use user ID for authenticated requests
$user = $request->getAttribute('user');
return $user ? "user:{$user->getId()}" : "ip:{$request->getClientIp()}";
}
private function getRoute(Request $request): string {
return $request->getRoute() ?? 'default';
}
}
Input Validation
Validating and sanitizing API input data.
Data Validation
Input validation, data sanitization, and security filtering create protection.
Proper validation prevents injection attacks and data corruption.
<?php
// Input Validation
class ApiValidator {
private $rules;
public function __construct(array $rules) {
$this->rules = $rules;
}
public function validate(array $data, string $ruleSet): array {
$rules = $this->rules[$ruleSet] ?? [];
$errors = [];
$sanitized = [];
foreach ($rules as $field => $fieldRules) {
$value = $data[$field] ?? null;
foreach ($fieldRules as $rule) {
$result = $this->applyRule($value, $rule);
if (!$result['valid']) {
$errors[$field][] = $result['message'];
} else {
$sanitized[$field] = $result['value'];
}
}
}
return [
'valid' => empty($errors),
'errors' => $errors,
'data' => $sanitized
];
}
private function applyRule($value, string $rule): array {
$parts = explode(':', $rule);
$ruleName = $parts[0];
$parameters = array_slice($parts, 1);
switch ($ruleName) {
case 'required':
return $this->validateRequired($value);
case 'email':
return $this->validateEmail($value);
case 'min':
return $this->validateMin($value, $parameters[0] ?? 0);
case 'max':
return $this->validateMax($value, $parameters[0] ?? 255);
case 'sanitize':
return $this->sanitize($value, $parameters[0] ?? 'string');
default:
return ['valid' => true, 'value' => $value];
}
}
private function validateRequired($value): array {
if ($value === null || $value === '') {
return [
'valid' => false,
'message' => 'This field is required',
'value' => $value
];
}
return ['valid' => true, 'value' => $value];
}
private function validateEmail($value): array {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
return [
'valid' => false,
'message' => 'Invalid email format',
'value' => $value
];
}
return ['valid' => true, 'value' => strtolower($value)];
}
private function sanitize($value, string $type): array {
switch ($type) {
case 'string':
$sanitized = filter_var($value, FILTER_SANITIZE_STRING);
break;
case 'int':
$sanitized = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
break;
case 'email':
$sanitized = filter_var($value, FILTER_SANITIZE_EMAIL);
break;
default:
$sanitized = $value;
}
return ['valid' => true, 'value' => $sanitized];
}
}
CORS Security
Implementing Cross-Origin Resource Sharing security.
CORS Protection
CORS security, cross-origin protection, and browser security create safety.
Proper CORS configuration prevents unauthorized cross-origin requests.
<?php
// CORS Security Middleware
class CorsMiddleware {
private $config;
public function __construct(array $config) {
$this->config = array_merge([
'allowed_origins' => ['*'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With'],
'max_age' => 86400,
'allow_credentials' => false
], $config);
}
public function handle(Request $request, callable $next): Response {
$origin = $request->getHeader('Origin');
$method = $request->getMethod();
// Handle preflight requests
if ($method === 'OPTIONS') {
return $this->handlePreflight($origin);
}
$response = $next($request);
// Add CORS headers to actual requests
if ($this->isOriginAllowed($origin)) {
$response->withHeaders([
'Access-Control-Allow-Origin' => $this->getAllowedOrigin($origin),
'Access-Control-Allow-Methods' => implode(', ', $this->config['allowed_methods']),
'Access-Control-Allow-Headers' => implode(', ', $this->config['allowed_headers']),
'Access-Control-Max-Age' => $this->config['max_age']
]);
if ($this->config['allow_credentials']) {
$response->withHeader('Access-Control-Allow-Credentials', 'true');
}
}
return $response;
}
private function handlePreflight(string $origin): Response {
if (!$this->isOriginAllowed($origin)) {
return new Response('CORS policy violation', 403);
}
return new Response('', 200, [
'Access-Control-Allow-Origin' => $this->getAllowedOrigin($origin),
'Access-Control-Allow-Methods' => implode(', ', $this->config['allowed_methods']),
'Access-Control-Allow-Headers' => implode(', ', $this->config['allowed_headers']),
'Access-Control-Max-Age' => $this->config['max_age'],
'Access-Control-Allow-Credentials' => $this->config['allow_credentials'] ? 'true' : 'false'
]);
}
private function isOriginAllowed(string $origin): bool {
if (in_array('*', $this->config['allowed_origins'])) {
return true;
}
return in_array($origin, $this->config['allowed_origins']);
}
private function getAllowedOrigin(string $origin): string {
if (in_array('*', $this->config['allowed_origins'])) {
return '*';
}
return $origin;
}
}
Security Headers
Implementing security headers for API protection.
Header Security
Security headers, HTTP protection, and browser security create defense.
Security headers protect against various web vulnerabilities.
<?php
// Security Headers Middleware
class SecurityHeadersMiddleware {
private $config;
public function __construct(array $config = []) {
$this->config = array_merge([
'X-Content-Type-Options' => 'nosniff',
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block',
'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains',
'Content-Security-Policy' => "default-src 'self'",
'Referrer-Policy' => 'strict-origin-when-cross-origin'
], $config);
}
public function handle(Request $request, callable $next): Response {
$response = $next($request);
foreach ($this->config as $header => $value) {
$response->withHeader($header, $value);
}
return $response;
}
}
// Security Audit Logger
class SecurityAuditLogger {
private $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function logAuthenticationAttempt(string $identifier, bool $success, string $method): void {
$this->logger->info('Authentication attempt', [
'identifier' => $identifier,
'success' => $success,
'method' => $method,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
'timestamp' => date('Y-m-d H:i:s')
]);
}
public function logSecurityEvent(string $event, array $context = []): void {
$this->logger->warning('Security event', array_merge([
'event' => $event,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
'timestamp' => date('Y-m-d H:i:s')
], $context));
}
public function logRateLimitExceeded(string $identifier, string $route): void {
$this->logger->warning('Rate limit exceeded', [
'identifier' => $identifier,
'route' => $route,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'timestamp' => date('Y-m-d H:i:s')
]);
}
}
Testing Security
Testing API security implementations.
Security Testing
Security testing, penetration testing, and vulnerability assessment create assurance.
Comprehensive testing ensures security measures work effectively.
<?php
// Security Testing
class ApiSecurityTest extends TestCase {
private $httpClient;
private $baseUrl;
protected function setUp(): void {
$this->httpClient = new HttpClient();
$this->baseUrl = getenv('API_BASE_URL');
}
public function testJwtAuthentication(): void {
// Test valid authentication
$loginResponse = $this->httpClient->post("{$this->baseUrl}/auth/login", [
'email' => 'test@example.com',
'password' => 'password123'
]);
$this->assertEquals(200, $loginResponse->getStatusCode());
$loginData = json_decode($loginResponse->getBody(), true);
$this->assertArrayHasKey('token', $loginData);
// Test authenticated request
$protectedResponse = $this->httpClient->get("{$this->baseUrl}/api/protected", [
'Authorization' => "Bearer {$loginData['token']}"
]);
$this->assertEquals(200, $protectedResponse->getStatusCode());
// Test invalid token
$invalidResponse = $this->httpClient->get("{$this->baseUrl}/api/protected", [
'Authorization' => 'Bearer invalid_token'
]);
$this->assertEquals(401, $invalidResponse->getStatusCode());
}
public function testRateLimiting(): void {
// Make multiple requests to trigger rate limit
for ($i = 0; $i < 10; $i++) {
$response = $this->httpClient->get("{$this->baseUrl}/api/test");
if ($i < 5) {
$this->assertEquals(200, $response->getStatusCode());
} else {
$this->assertEquals(429, $response->getStatusCode());
break;
}
}
}
public function testInputValidation(): void {
// Test invalid input
$invalidResponse = $this->httpClient->post("{$this->baseUrl}/api/users", [
'email' => 'invalid-email',
'name' => ''
]);
$this->assertEquals(400, $invalidResponse->getStatusCode());
$errors = json_decode($invalidResponse->getBody(), true);
$this->assertArrayHasKey('errors', $errors);
}
public function testCorsHeaders(): void {
$response = $this->httpClient->options("{$this->baseUrl}/api/test", [
'Origin' => 'https://example.com'
]);
$this->assertEquals(200, $response->getStatusCode());
$this->assertNotEmpty($response->getHeader('Access-Control-Allow-Origin'));
}
}
Conclusion: API Security
Comprehensive API security protects applications while enabling legitimate access.
Security Excellence
As security evolves, PHP APIs create opportunities for secure application development.
The transformation of API security through modern PHP represents hope for protected, scalable systems.
Comments (0)
No comments yet. Be the first to share your thoughts!