SignedURL
The expiry timestamp is part of the signed payload, not a separate query parameter an attacker could tamper with independently — extending it invalidates the signature.
Methods
SignedURL::sign(string $url, int $ttlSeconds, string $secret): string
SignedURL::verify(string $signedUrl, string $secret): bool // false if the signature is wrong OR it has expired
$link = SignedURL::sign('https://monad.dev/files/report.pdf', 3600, $secret);
// https://monad.dev/files/report.pdf?expires=1786160273&signature=4e4342d5...
SignedURL::verify($link, $secret); // true
SignedURL::verify($link, 'wrong-secret'); // false
SignedURL::verify($expiredLink, $secret); // false — expires timestamp already passed
Query parameters are sorted by key before signing, so a signed URL's parameter order never affects whether it verifies.
Next steps
- HMAC — what actually signs and verifies the payload.