A primitive for issuing and verifying signed, time-limited URLs using HMAC-SHA256. No external dependencies, no storage — the signature and expiry are query parameters on the URL itself.
A signed URL carries two extra query parameters:
https://example.com/files/report.pdf?exp=1747123456&sig=<hex>
exp is a Unix timestamp. sig is the hex-encoded HMAC-SHA256 of host:path:exp:canonical_query, where canonical_query is all query parameters except exp and sig, sorted by key. Altering the host, path, expiry, or any query parameter invalidates the signature. Comparison is done in constant time.
go get lowbit.dev/urlsigns, err := urlsign.NewSigner([]byte("secret"), time.Hour)
if err != nil {
// ErrEmptyKey or ErrInvalidTTL
}
// Sign a URL
signed, err := s.Sign("https://example.com/files/report.pdf")
// Verify a raw URL string
err = s.Verify(signed)
// Verify inside an HTTP handler
err = s.VerifyRequest(r)| Error | Meaning |
|---|---|
ErrEmptyKey |
Key passed to NewSigner was empty |
ErrInvalidTTL |
TTL passed to NewSigner was zero or negative |
ErrMissingParams |
URL is missing exp or sig |
ErrExpired |
URL's expiry is in the past |
ErrInvalidSig |
Signature does not match |
All errors can be checked with errors.Is.