Installation
composer require damax/api-auth-bundle
Add to config/bundles.php:
Damax\ApiAuthBundle\DamaxApiAuthBundle::class => ['all' => true],
Basic Configuration Publish the default config:
php bin/console damax:api-auth:install
Edit config/packages/damax_api_auth.yaml to define:
api_key (storage, extractors, TTL)jwt (secret key, claims, refresh token settings)First Use Case: API Key Auth
php bin/console damax:api-auth:api-key:create --user-id=1 --name="Test Key"
GET /api/endpoint
Authorization: Bearer <api-key>
GET /api/endpoint?api_key=<api-key>
First Use Case: JWT Auth
/api/login endpoint (if using Symfony’s security).GET /api/protected
Authorization: Bearer <jwt-token>
Key Storage
api_key.storage.database with a custom ApiKey entity.
# config/packages/damax_api_auth.yaml
api_key:
storage:
database: true
api_key.storage.redis and configure host/port.api_key.keys (for testing only).Key Extraction Chain
Customize the order of extractors (cookie, header, query) in api_key.extractors:
api_key:
extractors:
- header
- query
- cookie
TTL Management Set default TTL for keys:
api_key:
ttl: 3600 # 1 hour in seconds
Override per-key via CLI:
php bin/console damax:api-auth:api-key:create --user-id=1 --ttl=86400
Custom User Provider
Extend ApiKeyUserProvider to fetch users from non-standard sources (e.g., LDAP):
// src/Security/ApiKey/CustomApiKeyUserProvider.php
class CustomApiKeyUserProvider extends ApiKeyUserProvider
{
protected function loadUserByApiKey($apiKey)
{
// Custom logic here
}
}
Register in services.yaml:
services:
Damax\ApiAuthBundle\Security\ApiKey\ApiKeyUserProvider:
alias: App\Security\ApiKey\CustomApiKeyUserProvider
Token Generation
Use Symfony’s authentication_utils or a custom controller:
use Damax\ApiAuthBundle\Security\Authenticator\JwtAuthenticator;
// In a controller
$token = $this->get('lexik_jwt_authentication.jwt_manager')->create($payload);
Custom Claims Add claims to the JWT payload:
# config/packages/damax_api_auth.yaml
jwt:
claims:
custom:
role: ROLE_API_USER
scope: ['read', 'write']
Refresh Tokens Enable refresh token support:
jwt:
refresh_token:
enabled: true
ttl: 86400 # 24 hours
Implement a /refresh endpoint to handle token rotation.
Response Customization
Override default success/error responses by extending the JwtAuthenticator:
// src/Security/Authenticator/CustomJwtAuthenticator.php
class CustomJwtAuthenticator extends JwtAuthenticator
{
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName)
{
return new JsonResponse(['token' => $token->getCredentials()]);
}
}
Firewall Configuration
Add to security.yaml:
firewalls:
api:
pattern: ^/api
stateless: true
json_login:
check_path: /api/login
username_path: username
password_path: password
jwt: ~
api_key: ~
Role-Based Access Use Symfony’s voter system or custom logic to restrict endpoints:
// src/Security/Voter/ApiKeyVoter.php
class ApiKeyVoter extends Voter
{
protected function supports(string $attribute, mixed $subject): bool
{
return $attribute === 'ROLE_API_KEY';
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
// Custom logic
}
}
Extractor Order Matters
api_key is passed in both header and query, the first extractor in the chain wins.php bin/console debug:config damax_api_auth
Case Sensitivity
ApiKeyUserProvider if needed:
$apiKey = strtolower($apiKey);
TTL Edge Cases
ttl: 0 are permanent. Set to null to disable TTL entirely.Concurrent Requests
Key Revocation
revoked_keys Redis set or database flag:
php bin/console damax:api-auth:api-key:revoke --key=<key-id>
Symmetric vs. Asymmetric
jwt:
secret_key: "%kernel.project_dir%/config/jwt/private.pem"
public_key: "%kernel.project_dir%/config/jwt/public.pem"
Token Size Limits
Clock Skew
nbf (not before) and exp (expiry) claims. Ensure server time is synchronized:
jwt:
leeway: 30 # Allow 30-second clock skew
Refresh Token Security
Custom Claims Serialization
JsonSerializable or be JSON-serializable:
$payload['custom_claim'] = new class implements JsonSerializable {
public function jsonSerialize() { return ['data' => 'value']; }
};
Enable Verbose Logging
# config/packages/monolog.yaml
handlers:
api_auth:
type: stream
path: "%kernel.logs_dir%/api_auth.log"
level: debug
CLI Commands
php bin/console damax:api-auth:api-key:list
php bin/console damax:api-auth:api-key:lookup --key=<key>
Event Listeners
api_key.authenticated and jwt.authenticated events for custom logic:
// src/EventListener/AuthListener.php
class AuthListener
{
public function onApiKeyAuthenticated(ApiKeyAuthenticatedEvent $event)
{
// Log or modify user data
}
}
Testing
ApiKeyFactory in PHPUnit:
$apiKey = $this->get('damax_api_auth.api_key.factory')->create('user1', ['role' => 'ROLE_TEST']);
JwtManager for JWT tests:
$this->mock(JwtManager::class)->shouldReceive('create')->once();
ApiKeyStorageInterface for non-RedisHow can I help you explore Laravel packages today?