CorsMiddleware - viames/pair GitHub Wiki
Pair framework: CorsMiddleware
Pair\Api\CorsMiddleware handles Cross-Origin Resource Sharing for Pair APIs.
It is the middleware you use when browser clients call your API from another origin.
Constructor
new CorsMiddleware(array $options = [])
Supported options in the current implementation:
allowedOriginsDefault:['*']allowedMethodsDefault:['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']allowedHeadersDefault includesContent-Type,Authorization,X-Requested-WithmaxAgeDefault:86400
Example:
// Allows all origins with the default methods and headers.
$this->middleware(new \Pair\Api\CorsMiddleware());
Main method
handle(Request $request, callable $next): mixed
This is the main method of the class.
Current behavior:
- sets CORS headers for the response
- if the request method is
OPTIONS, returns an explicit HTTP204response - otherwise forwards the request to the next middleware or action
Example:
public function handle(\Pair\Api\Request $request, callable $next): mixed
{
// Sets the Access-Control-* headers.
// If this is a preflight request, the middleware returns a 204 response.
// Otherwise it continues with the next middleware.
}
Origin handling
Wildcard origin
When allowedOrigins contains '*', the middleware emits:
Access-Control-Allow-Origin: *
Explicit origin allow-list
When you pass a list of allowed origins, the middleware:
- reads the request
Originheader - echoes that origin back only if it is in the allow-list
- adds
Vary: Origin
Example:
$this->middleware(new \Pair\Api\CorsMiddleware([
'allowedOrigins' => [
'https://app.example.com',
'https://admin.example.com',
],
'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
'allowedHeaders' => ['Content-Type', 'Authorization', 'Idempotency-Key'],
'maxAge' => 3600,
]));
Preflight behavior
For OPTIONS requests the middleware:
- sends the CORS headers
- returns an explicit
TextResponsewith HTTP status204 - short-circuits the middleware chain without exiting directly
That is why CORS middleware often needs to run before auth or throttling for browser-facing APIs.
Practical controller example
protected function registerDefaultMiddleware(): void
{
// Handles browser preflight requests first.
$this->middleware(new \Pair\Api\CorsMiddleware([
'allowedOrigins' => ['https://app.example.com'],
'allowedHeaders' => ['Content-Type', 'Authorization', 'Idempotency-Key'],
]));
// Applies throttling after CORS.
$this->middleware(new \Pair\Api\ThrottleMiddleware(60, 60));
}
Important implementation notes
These details reflect the current code:
- the middleware always sends
Access-Control-Allow-Methods,Access-Control-Allow-Headers, andAccess-Control-Max-Age Access-Control-Allow-Originis sent only for wildcard mode or for an explicitly matched origin- there is no built-in
Access-Control-Allow-Credentialssupport in this middleware
If your frontend needs credentialed cross-origin requests, document and implement that intentionally instead of assuming it is already handled.
Common pitfalls
- Putting CORS middleware after auth or throttling and breaking preflight
OPTIONS. - Using
'*'in production for sensitive APIs without reviewing the risk profile. - Forgetting to allow custom client headers such as
Idempotency-Keyor tenant headers. - Assuming credentials support exists out of the box when it does not.
See also: MiddlewarePipeline, ThrottleMiddleware, Middleware, API.