Here's what happens when a request arrives:
Client sends: GET /api/licenses
Header: Authorization: Bearer abc123
↓
Router matches route, checks middleware
↓
EnsureTokenIsValidMiddleware:
- Extract token "abc123"
- Cache key: "bearer:abc123"
- Cache hit? Return cached Bearer model
- Cache miss? Query database, cache, return
- Valid? Not expired? Domain matches?
→ If yes, continue
→ If no, return 401
↓
throttle:api-token:
- Check rate limit for token
- 60 per minute, 45 remaining?
→ If under limit, continue
→ If over limit, return 429
↓
AddRateLimitHeadersMiddleware:
- Calculate remaining quota
- Add headers: X-RateLimit-*
↓
LogApiRequestsMiddleware:
- Set defer callback to log this request
- Continue to controller
↓
LicenseServiceProvider::boot():
- Inspect token settings
- Set Config to use correct driver
- Set driver credentials from token
↓
LicenseController::show():
- Call LicenseFacade::licenses()
- Facade uses configuration from token
- Returns LicenseDTO[]
- Maps to LicenseResource
- Wraps in CollectionResponse
↓
Response flows back through middleware (bottom to top)
↓
LogApiRequestsMiddleware:
- Execute deferred callback
- Queue SendToLogsJob
- (Happens asynchronously, doesn't block response)
↓
Response sent to client with:
- Status 200
- Rate limit headers
- JSON body
↓
SendToLogsJob executes in queue:
- Write log entry with request details
- Token hashed, not exposed
- Audit trail complete
All of this happens automatically. No controller code has to think about authentication, rate limiting, logging, or configuration. It's all enforced by middleware, all consistent, all proven.
Testing Authentication
Security patterns are only valuable if they're tested. Test everything:
test('valid bearer token is accepted', function () {
$bearer = Bearer::factory()->create();
$response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
->get('/api/licenses');
expect($response->status())->toBe(200);
});
test('missing token is rejected', function () {
$response = $this->get('/api/licenses');
expect($response->status())->toBe(401);
});
test('expired token is rejected', function () {
$bearer = Bearer::factory()->expired()->create();
$response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
->get('/api/licenses');
expect($response->status())->toBe(401);
});
test('token is rejected if domain does not match', function () {
$bearer = Bearer::factory()
->withDomains(['https://allowed-domain.com'])
->create();
$response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
->get('/api/licenses');
expect($response->status())->toBe(401);
});
test('rate limit is enforced', function () {
$bearer = Bearer::factory()->create();
$token = $bearer->token;
for ($i = 0; $i < 60; $i++) {
$this->withHeader('Authorization', "Bearer $token")
->get('/api/licenses');
}
$response = $this->withHeader('Authorization', "Bearer $token")
->get('/api/licenses');
expect($response->status())->toBe(429);
});
Each test verifies one security guarantee. Collectively, they ensure your authentication layer is solid.