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.