Documentation
¶
Overview ¶
Package securecookie encodes and decodes authenticated and encrypted cookie values.
Cookie values are serialized (JSON by default), sealed together with a timestamp using XChaCha20-Poly1305, and base64-encoded. The cookie name is bound to the ciphertext as additional authenticated data, so a value issued for one cookie name cannot be replayed under another. The timestamp is validated against MinAge/MaxAge before the payload is deserialized.
Basic usage:
key := securecookie.GenerateRandomKey(32) // persist this somewhere!
s, err := securecookie.New(key, nil)
if err != nil {
// ...
}
// Encode a value into a cookie.
encoded, err := s.Encode("session", map[string]string{"user": "42"})
// Decode it back.
value := map[string]string{}
ts, err := s.Decode("session", encoded, &value)
To rotate keys, pass the previous keys in Options.RotatedKeys. New cookies are always encrypted with the primary key; rotated keys are only tried when decoding, so cookies issued before the rotation stay valid until they expire:
s, err := securecookie.New(newKey, &securecookie.Options{
RotatedKeys: [][]byte{oldKey},
})
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrKeyLength = fmt.Errorf("the key must be %d bytes", chacha20poly1305.KeySize) ErrDecryptionFailed = fmt.Errorf("the value could not be decrypted") ErrValueNotByte = fmt.Errorf("the value is not a []byte") ErrValueNotBytePtr = fmt.Errorf("the value is not a *[]byte") ErrValueTooLong = fmt.Errorf("the value is too long") ErrTimestampInvalid = fmt.Errorf("the timestamp is invalid") ErrTimestampTooNew = fmt.Errorf("the timestamp is too new") ErrTimestampExpired = fmt.Errorf("the timestamp is expired") )
var DefaultOptions = &Options{ MinAge: 0, MaxAge: 86400 * 30, MaxLength: 4096, Serializer: JSONEncoder{}, TimeFunc: defaultTimeFunc, }
Functions ¶
func GenerateRandomKey ¶
GenerateRandomKey creates a random key with the given length in bytes. It panics if the system's secure random number source fails, in which case the process should not continue.
Note that keys created using `GenerateRandomKey()` are not automatically persisted. New keys will be created when the application is restarted, and previously issued cookies will not be able to be decoded.
Types ¶
type Codec ¶
type Codec interface {
Encode(name string, value any) (string, error)
Decode(name, value string, dst any) (int64, error)
}
Codec defines an interface to encode and decode cookie values.
type GobEncoder ¶
type GobEncoder struct{}
GobEncoder encodes cookie values using encoding/gob. This is the simplest encoder and can handle complex types via gob.Register.
func (GobEncoder) Deserialize ¶
func (e GobEncoder) Deserialize(src []byte, dst any) error
Deserialize decodes a value using gob.
type JSONEncoder ¶
type JSONEncoder struct{}
JSONEncoder encodes cookie values using encoding/json. Users who wish to encode complex types need to satisfy the json.Marshaller and json.Unmarshaller interfaces.
func (JSONEncoder) Deserialize ¶
func (e JSONEncoder) Deserialize(src []byte, dst any) error
Deserialize decodes a value using encoding/json.
type NopEncoder ¶
type NopEncoder struct{}
NopEncoder does not encode cookie values, and instead simply accepts a []byte (as an any) and returns a []byte. This is particularly useful when you encoding an object upstream and do not wish to re-encode it.
func (NopEncoder) Deserialize ¶
func (e NopEncoder) Deserialize(src []byte, dst any) error
Deserialize passes a []byte through as-is.
type Options ¶
type Options struct {
// RotatedKeys holds previous keys, tried in order when decoding so that
// cookies issued before a key rotation remain valid. They are never used
// for encoding. Each key must be 32 bytes.
RotatedKeys [][]byte
// MinAge is the minimum age of a cookie, in seconds. Cookies encoded
// less than MinAge seconds ago are rejected. 0 disables the check.
MinAge int64
// MaxAge is the maximum age of a cookie, in seconds. Cookies encoded
// more than MaxAge seconds ago are rejected. 0 disables the check.
MaxAge int64
// MaxLength is the maximum length of an encoded cookie value, in bytes.
// 0 disables the check. Note that browsers commonly limit the whole
// cookie (name, value and attributes) to 4096 bytes.
MaxLength int
// Serializer converts values to and from bytes. Defaults to JSONEncoder.
Serializer Serializer
// TimeFunc returns the current Unix timestamp, in seconds. It exists so
// tests can supply a fake clock. Defaults to time.Now().UTC().Unix().
TimeFunc func() int64
}
type SecureCookie ¶
type SecureCookie struct {
// contains filtered or unexported fields
}
SecureCookie encodes and decodes authenticated and encrypted cookie values. It is safe for concurrent use by multiple goroutines, as long as the configured Serializer and TimeFunc are (the defaults are).
func New ¶
func New(key []byte, options *Options) (*SecureCookie, error)
New returns a new SecureCookie.
Key is required and must be 32 bytes, used to authenticate and encrypt cookie values. The same length requirement applies to every key in options.RotatedKeys.
If options is nil, DefaultOptions is used. The provided Options value is only read, never modified.
Note that keys created using GenerateRandomKey() are not automatically persisted. New keys will be created when the application is restarted, and previously issued cookies will not be able to be decoded.
func (*SecureCookie) Decode ¶
func (s *SecureCookie) Decode(name, value string, dst any) (int64, error)
Decode decodes a cookie value.
It decodes the base64 value, decrypts and verifies the ciphertext, checks the embedded timestamp against MinAge/MaxAge, and finally deserializes the value into dst, which must be a pointer.
The name argument is the cookie name. It must be the same name used when it was encoded.
It returns the timestamp at which the cookie was encoded whenever it is known, even if a timestamp or deserialization error is returned alongside.
func (*SecureCookie) Encode ¶
func (s *SecureCookie) Encode(name string, value any) (string, error)
Encode encodes a cookie value.
It serializes the value, encrypts and authenticates it together with a timestamp using the primary key, and finally encodes the result with base64. Rotated keys are never used for encoding.
The name argument is the cookie name. It is bound to the ciphertext as additional authenticated data, so a value issued for one cookie name cannot be replayed under another.