Documentation
¶
Overview ¶
Package signed creates and verifies signed URLs: links that carry an expiry and an HMAC-SHA256 signature over their path and query, for email verification, unsubscribe links or temporary downloads.
key, err := app.DeriveKey("signed.urls", 32) // fails without APP_KEY
if err != nil {
return err
}
s := signed.New(key).
WithPreviousKeys(app.DerivePreviousKeys("signed.urls", 32)...).
WithClock(app.Now)
link, _ := s.Sign(appURL+"/email/verify/42", time.Hour)
r.Get("/email/verify/{id}", verify).Use(s.Middleware())
Signer.Verify checks a request in constant time and returns ErrInvalid or ErrExpired; Signer.Middleware answers 403 for both.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/security.md.
Example ¶
package main
import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"time"
"github.com/AlexGalhardo/vukem/signed"
)
func main() {
// In an app, derive the key: app.Key.Derive("signed.urls", 32).
s := signed.New(bytes.Repeat([]byte{3}, 32))
link, err := s.Sign("https://example.com/email/verify/42", time.Hour)
if err != nil {
fmt.Println(err)
return
}
ok := httptest.NewRequest(http.MethodGet, link, http.NoBody)
fmt.Println(s.Verify(ok) == nil)
tampered := httptest.NewRequest(http.MethodGet, strings.Replace(link, "/42", "/43", 1), http.NoBody)
fmt.Println(s.Verify(tampered) == nil)
}
Output: true false
Index ¶
Examples ¶
Constants ¶
const MinKeyLen = 32
MinKeyLen is the minimum signing key length; New panics below it.
Variables ¶
var ( ErrInvalid = &errs.HTTPError{Status: http.StatusForbidden, Message: "Invalid signature."} ErrExpired = &errs.HTTPError{Status: http.StatusForbidden, Message: "This link has expired."} )
Errors returned by Verify (403 for clients).
Functions ¶
This section is empty.
Types ¶
type Signer ¶
type Signer struct {
// contains filtered or unexported fields
}
Signer signs URLs with one key and verifies them with that key or any previous key (APP_KEY rotation, see WithPreviousKeys).
func New ¶
New returns a Signer; derive key from APP_KEY (app.DeriveKey). It panics when key is shorter than MinKeyLen.
func (*Signer) Middleware ¶
Middleware rejects requests whose URL signature is missing, wrong or expired with 403 (and an "url.signature_invalid" security event).
func (*Signer) Sign ¶
Sign adds "expires" (Unix seconds; ttl 0 means no expiry) and "signature" query parameters to rawURL. Only the path and query are signed, so links keep working behind proxies and on other hosts.
func (*Signer) WithClock ¶ added in v0.28.0
WithClock makes s read the time from now (pass app.Now, so a vukemtest fake clock expires links); nil keeps the system clock. Call it before s is used.
func (*Signer) WithPreviousKeys ¶ added in v0.26.0
WithPreviousKeys makes s also accept links signed with keys (derive them with app.DerivePreviousKeys, from APP_PREVIOUS_KEYS), so links sent before an APP_KEY rotation keep working until the old key is removed. Sign always uses the current key. Call it before s is used; it panics when a key is shorter than MinKeyLen, like New.