> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Manejar correctamente la entrada de URLs firmadas

> Explicamos qué protegen las URLs firmadas en Laravel 13 y por qué conviene obtener los valores de consulta firmados con query(), con un ejemplo de enlace con caducidad.

## Objetivo de esta página

Si quieres que un enlace compartido con caducidad use exactamente las condiciones definidas al emitirlo, además de verificar la firma de la URL debes ser coherente con **de dónde obtienes los valores**.
En esta página lo explicamos con un ejemplo que incluye el tipo de informe y el formato de salida en la URL y devuelve un JSON de vista previa.

El contenido corresponde a Laravel 13. Para la generación de URLs en general, consulta [Generación de URLs](/es/urls), y para los fundamentos de la obtención de entrada, [Solicitudes HTTP](/es/requests).

<Warning>
  La firma no protege toda la solicitud. Los cuerpos de formularios y JSON no se firman.
  Obtén los valores de consulta firmados después de verificar la firma, por ejemplo con `$request->query('format')`.
  Con `input()`, `all()` o las propiedades dinámicas podrías obtener valores del cuerpo que no están firmados. Esta distinción también es necesaria en las solicitudes GET.
</Warning>

## Qué protege la firma

| Elemento | Tratamiento |
| - | - |
| Ruta de la URL | Incluida en la verificación de la firma |
| Cadena de consulta | Incluida, en principio, en la verificación de la firma, salvo los parámetros que excluyas de la verificación |
| Esquema y host | Normalmente se incluyen en la firma. No se incluyen en las firmas relativas |
| Cuerpo de formularios y JSON | No forma parte de la firma |
| Fecha de caducidad | La añade `temporarySignedRoute()` y se comprueba si ha caducado durante la verificación |

`input()` es una API que maneja no solo la cadena de consulta, sino también el cuerpo. Al combinar estas entradas, Laravel da prioridad a los valores del cuerpo sobre los de la cadena de consulta.
En cambio, `query()` obtiene únicamente la cadena de consulta.

Que la verificación de la firma haya tenido éxito y que un valor leído después esté firmado son dos comprobaciones distintas.

```mermaid theme={null}
flowchart TD
    A["Acceso mediante URL con caducidad"] --> B{"Middleware signed<br>Verifica firma y caducidad"}
    B -->|No válida| C["Respuesta 403"]
    B -->|Válida| D["Obtener valores de consulta<br>firmados con query()"]
    D --> E["Validar formato y rango permitido de los valores"]
    E --> F["Devolver la vista previa"]
```

## Implementar un enlace de vista previa con caducidad

### 1. Definir la ruta que se verifica

En `routes/web.php`, define una ruta con nombre que exija firma.
Este ejemplo no accede a la base de datos ni a archivos; solo devuelve las condiciones recibidas.

```php theme={null}
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;

Route::get('/reports/preview', function (Request $request) {
    $options = Validator::make([
        'report' => $request->query('report'),
        'format' => $request->query('format'),
    ], [
        'report' => ['required', 'string', 'in:monthly,annual'],
        'format' => ['required', 'string', 'in:csv,pdf'],
    ])->validate();

    return response()->json($options);
})->middleware('signed')->name('reports.preview');
```

* El middleware `signed` verifica la firma y la caducidad antes de ejecutar el closure. Si no son válidas, devuelve `403`.
* Con `query()` obtienes explícitamente de la cadena de consulta los valores que se usan en el procesamiento.
* La validación se aplica al array obtenido. La verificación de la firma no garantiza el tipo de los valores ni los rangos permitidos por la lógica de negocio.

<Info>
  En este ejemplo, a `Validator::make()` solo se le pasan los valores extraídos con `query()`.
  Si los sustituyes por `$request->all()` en un punto cuyo objetivo es validar la consulta firmada, acabarás manejando una entrada que incluye el cuerpo.
</Info>

### 2. Generar la URL en un proceso de emisión de confianza

Después de registrar la ruta con nombre, usa el siguiente código en el proceso que emite los enlaces.
Como `report` y `format` no son marcadores de posición de la ruta, se añaden a la cadena de consulta.

```php theme={null}
use Illuminate\Support\Facades\URL;

$url = URL::temporarySignedRoute(
    'reports.preview',
    now()->addMinutes(30),
    ['report' => 'monthly', 'format' => 'csv'],
);
```

Además de las condiciones indicadas, esta URL contiene `expires` y `signature`.
`expires` y `signature` son parámetros reservados que usa Laravel, así que no los utilices como nombres de tus propios parámetros de negocio.

Si expones el proceso de emisión en una aplicación real, no permitas que cualquiera pueda emitir enlaces con condiciones arbitrarias; aplica la [autenticación](/es/authentication) y la [autorización](/es/authorization) necesarias.

### 3. Comprobar el uso normal

Si abres la URL emitida tal cual dentro del plazo de validez, se devuelve el siguiente JSON.

```json theme={null}
{
  "report": "monthly",
  "format": "csv"
}
```

Si el enlace ha caducado, el middleware `signed` de la ruta devuelve `403`.
Las URLs firmadas no son tokens de un solo uso. En este ejemplo, la misma URL puede reutilizarse mientras siga vigente.
Si quieres que un enlace solo se use una vez, debes gestionar el estado de uso por separado de la firma.

## Separar los valores excluidos de la verificación

Si quieres permitir valores como el número de página que añade el frontend, puedes excluirlos de la verificación de la firma con `hasValidSignatureWhileIgnoring(['page'])`.
Sin embargo, cualquiera puede modificar los valores excluidos, así que no los trates como condiciones firmadas.

Por ejemplo, `page`, que sirve para la visualización, cumple una función distinta de `report` y `format`, que se fijan al emitir el enlace.
No excluyas por simple comodidad los valores que se usan para decidir los datos de destino, los destinatarios, los precios, etc.

<Warning>
  El ejemplo anterior usa el middleware `signed` normal, por lo que tampoco excluye `page`.
  Si quieres añadir parámetros de consulta, decide primero qué se firmará tanto en el lado que genera como en el que verifica.
</Warning>

## Usar firmas relativas

Si tu diseño no incluye el dominio en la firma, combina `absolute: false` al generar con `signed:relative` al verificar.

```php theme={null}
$url = URL::temporarySignedRoute(
    'reports.preview',
    now()->addMinutes(30),
    ['report' => 'monthly', 'format' => 'csv'],
    absolute: false,
);
```

En este caso, cambia `middleware('signed')` de la ruta anterior por `middleware('signed:relative')`.
Con las firmas relativas el cuerpo tampoco se firma, así que se mantiene el criterio de obtener los valores con `query()`.

## Lista de comprobación para la implementación

* La ruta receptora exige la verificación de la firma.
* Los valores de consulta firmados se obtienen con `query()`.
* El formato y el rango permitido de los valores se validan por separado.
* Los valores excluidos de la verificación de la firma no se usan como condiciones fijadas al emitir el enlace.
* La configuración de firma absoluta o relativa coincide en el lado que genera y en el que verifica.
* Conocer la URL no se considera equivalente a los permisos del usuario autenticado.

## Páginas relacionadas y fuentes primarias

* [Generación de URLs](/es/urls): API de URLs firmadas y respuesta a firmas no válidas
* [Solicitudes HTTP](/es/requests): obtención de valores de entrada y de la cadena de consulta
* [Validación](/es/validation): validación del formato de entrada y de los valores permitidos
* [Documentación oficial de Laravel: Signed URLs](https://github.com/laravel/docs/blob/13.x/urls.md#signed-urls)
* [Documentación oficial de Laravel: Retrieving input from the query string](https://github.com/laravel/docs/blob/13.x/requests.md#retrieving-input-from-the-query-string)
* [Laravel Framework: UrlGenerator](https://github.com/laravel/framework/blob/13.x/src/Illuminate/Routing/UrlGenerator.php)
* [Laravel Framework: ValidateSignature](https://github.com/laravel/framework/blob/13.x/src/Illuminate/Routing/Middleware/ValidateSignature.php)


## Related topics

- [Generación de URLs](/es/urls.md)
- [Basic client - Laravel Bluesky](/es/packages/laravel-bluesky/basic-client.md)
- [Laravel Boost](/es/boost.md)
- [Fusión y caché de la configuración de paquetes](/es/advanced/package-config-merging.md)
- [Guía de desarrollo de apps con integración de la Engine API - VOICEVOX for Laravel](/es/packages/laravel-voicevox/app-guide.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.