Awesome
cookie
Cookies, but with structs, for happiness.
Overview
cookie
is a Go package designed to make handling HTTP cookies simple and
robust, and simplifying the process of parsing them into your structs. It
supports standard data types, custom data types, and signed cookies to ensure
data integrity.
Features
- Easy to use: Simple API for managing cookies in your web applications.
- Struct-based cookie values: Easily get cookies into your structs.
- Custom type support: Extend cookie parsing with your own data types.
- Signed cookies: Ensure the integrity of your cookies with HMAC signatures.
- No external dependencies: Just pure standard library goodness.
Installation
go get github.com/syntaqx/cookie
Basic Usage
The cookie
package provides a DefaultManager
that can be used to plug and
play into your existing applications:
cookie.Get(r, "DEBUG")
cookie.GetSigned(r, "Access-Token")
cookie.Set(w, "DEBUG", "true", cookie.Options{})
cookie.Set(w, "Access-Token", "token_value", cookie.Options{Signed: true})
cookie.SetSigned(w, "Access-Token", "token_value")
Or Populate a struct:
type RequestCookies struct {
Theme string `cookie:"THEME"`
Debug bool `cookie:"DEBUG,unsigned"`
AccessToken string `cookie:"Access-Token,signed"`
}
var c RequestCookies
cookie.PopulateFromCookies(r, &c)
In order to sign cookies however, you must provide a signing key:
signingKey := []byte("super-secret-key")
cookie.DefaultManager = cookie.NewManager(
cookie.WithSigningKey(signingKey),
)
[!TIP] Cookies are stored in plaintext by default (unsigned). A signed cookie is used to ensure the cookie value has not been tampered with. This is done by creating a HMAC signature of the cookie value using a secret key. Then, when the cookie is read, the signature is verified to ensure the cookie value has not been modified.
It is still recommended that sensitive data not be stored in cookies, and that HTTPS be used to prevent cookie replay attacks.
Advanced Usage: Manager
For more advanced usage, you can create a Manager
to handle your cookies,
rather than relying on the DefaultManager
:
manager := cookie.NewManager()
You can optionally provide a signing key for signed cookies:
signingKey := []byte("super-secret-key")
manager := cookie.NewManager(
cookie.WithSigningKey(signingKey),
)
Setting Cookies
Use the Set
method to set cookies. You can specify options such as path,
domain, expiration, and whether the cookie should be signed.
err := manager.Set(w, "DEBUG", "true", cookie.Options{})
err := manager.Set(w, "Access-Token", "token_value", cookie.Options{Signed: true})
Getting Cookies
Use the Get method to retrieve unsigned cookies and GetSigned for signed cookies.
value, err := manager.Get(r, "DEBUG")
value, err := manager.GetSigned(r, "Access-Token")
Populating Structs from Cookies
Use PopulateFromCookies
to populate a struct with cookie values. The struct
fields should be tagged with the cookie names.
type RequestCookies struct {
Theme string `cookie:"THEME"`
Debug bool `cookie:"DEBUG,unsigned"`
AccessToken string `cookie:"Access-Token,signed"`
NotRequired string `cookie:"NOT_REQUIRED,omitempty"`
}
var c RequestCookies
err := manager.PopulateFromCookies(r, &c)
[!TIP] By default, the
PopulateFromCookies
method will return an error if a required cookie is missing. You can use theomitempty
tag to make a field optional.
Supporting Custom Types
To support custom types, register a custom handler with the Manager.
import (
"reflect"
"github.com/gofrs/uuid/v5"
"github.com/syntaqx/cookie"
)
...
manager := cookie.NewManager(
cookie.WithSigningKey(signingKey),
cookie.WithCustomHandler(reflect.TypeOf(uuid.UUID{}), func(value string) (interface{}, error) {
return uuid.FromString(value)
}),
)