Ir al contenido principal
Laravel, shipping fast.

Las rutas protegidas se agrupan con middleware en un orden concreto:

// routes/api.php
Route::get('/health', HealthController::class);  // Public

Route::middleware([
    EnsureTokenIsValidMiddleware::class,
    'throttle:api-token',
    AddRateLimitHeadersMiddleware::class,
    LogApiRequestsMiddleware::class,
])->controller(LicenseController::class)->group(function () {
    Route::get('/licenses', 'show');
    Route::post('/license', 'create');
    Route::delete('/license/{license}', 'destroy');
});

El orden importa. El middleware corre de arriba abajo en la petición y de abajo arriba en la respuesta:

Camino de la petición:

  1. EnsureTokenIsValidMiddleware: valida que el token existe, no ha expirado y el dominio coincide. Si falla, rechaza con 401. Fin.
  2. throttle:api-token: comprueba si el token superó el límite. Si sí, devuelve 429. Fin.
  3. AddRateLimitHeadersMiddleware: añade las cabeceras de límite.
  4. LogApiRequestsMiddleware: encola un job de registro.
  5. Controlador: ejecuta la lógica del endpoint.

Este orden garantiza que las peticiones fallidas se detienen pronto. Una petición sin token nunca llega al límite de frecuencia. Una petición limitada nunca llega a tu controlador. Eso es eficiente y predecible.

Validacion de dominio: atar tokens a origenes

Los tokens pueden restringir desde qué dominios se les permite usarse. Es crucial en escenarios con socios.

Imagina que emites un token al Socio A. Prometen usarlo sólo desde partner-a.com. Pero ¿y si les roban las credenciales? Un atacante consigue el token pero opera desde attacker.com. Sin validación de dominio, el token sigue funcionando. Con ella, falla.

private function isTokenValidForDomain(Request $request, Bearer $token): bool
{
    $domains = $token->domains;

    // No domain config? Always allow
    if (empty($domains) || ! config('bearer.verify_domains', false)) {
        return true;
    }

    // Handle JSON storage edge case
    if (is_string($domains)) {
        $decoded = json_decode($domains, true);
        if (! is_array($decoded)) {
            return false;  // Malformed domains data
        }
        $domains = $decoded;
    }

    // Check if request origin is whitelisted
    return in_array($request->getSchemeAndHttpHost(), $domains, true);
}

getSchemeAndHttpHost() devuelve el origen completo: https://partner-a.com. Compararlo con la lista blanca garantiza que el token sólo funcione desde los dominios esperados.

El flujo completo de una peticion

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
    → 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()
    - Returns LicenseDTO[]
    - Maps to LicenseResource
    - Wraps in CollectionResponse


Response flows back through middleware (bottom to top)


SendToLogsJob executes in queue:
    - Write log entry with request details
    - Token hashed, not exposed

Todo esto ocurre automáticamente. Ningún código de controlador tiene que pensar en autenticación, límites, registro o configuración. Lo impone el middleware, todo consistente, todo probado.