Documentation
¶
Overview ¶
Package session keeps per-visitor state across requests in an encrypted cookie: values, flash messages, the CSRF token, and the validation errors and form input a failed form post leaves for the next page.
Add the middleware to the routes that serve HTML, then use the session from any request context:
sessions, err := session.ForApp(app) // SESSION_* settings, APP_KEY
web := r.Group("", sessions.Middleware, web.CSRF())
s := session.From(c)
s.Put("theme", "dark")
s.Flash("status", "Post saved.")
By default the cookie holds the whole session, encrypted and authenticated with APP_KEY, so there is nothing to store on the server; it is limited to about 4 KB. With SESSION_DRIVER=database (or redis, from drivers/redis) the session is kept in a store and the cookie holds its encrypted ID, so sessions can be revoked. Sessions end after SESSION_LIFETIME without a request.
Index ¶
- func Migrations(table string) *migrate.Set
- func NewContext(ctx context.Context, s *Session) context.Context
- func Value[T any](s *Session, key string) (T, bool)
- type Config
- type Driver
- type FieldError
- type Manager
- func (m *Manager) Config() Config
- func (m *Manager) CookieName() string
- func (m *Manager) Edit(r *http.Request, fn func(s *Session)) (*http.Cookie, error)
- func (m *Manager) Load(r *http.Request) *Session
- func (m *Manager) Middleware(next http.Handler) http.Handler
- func (m *Manager) Store() (cache.Store, string)
- func (m *Manager) Use(mw ...func(http.Handler) http.Handler)
- type Option
- type Session
- func (s *Session) Clear()
- func (s *Session) Delete(key string)
- func (s *Session) Errors() []FieldError
- func (s *Session) Flash(key string, v any)
- func (s *Session) FlashErrors(errs ...FieldError)
- func (s *Session) FlashInput(values url.Values)
- func (s *Session) Get(key string, dst any) bool
- func (s *Session) Has(key string) bool
- func (s *Session) ID() string
- func (s *Session) Invalidate()
- func (s *Session) Keep(keys ...string)
- func (s *Session) Old(field string) (string, bool)
- func (s *Session) OldInput() url.Values
- func (s *Session) Pull(key string, dst any) bool
- func (s *Session) Put(key string, v any)
- func (s *Session) Reflash()
- func (s *Session) Regenerate()
- func (s *Session) RegenerateToken()
- func (s *Session) String(key string) string
- func (s *Session) Token() string
- func (s *Session) VerifyToken(t string) bool
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Migrations ¶ added in v0.2.0
Migrations returns the migration creating the database driver's table (default "sessions"), for migrate.ForApp:
migrate.ForApp(app, []*migrate.Set{migrations.All, session.Migrations("")})
func NewContext ¶
NewContext returns ctx carrying s. The middleware does this; tests can use it to call handlers with a session.
Types ¶
type Config ¶
type Config struct {
// Cookie is the cookie's name. SESSION_COOKIE, default "anetos_session".
// A Secure cookie with the default Path and no Domain gets the
// "__Host-" prefix, so no other site (subdomains included) can set it.
Cookie string `env:"COOKIE" default:"anetos_session"`
// Lifetime is how long a session lasts without a request.
// SESSION_LIFETIME, default 2h.
Lifetime time.Duration `env:"LIFETIME" default:"2h"`
// MaxLifetime is how long a session lasts in all, however active: a
// copied cookie can't be used forever. Regenerate (at login) restarts
// it. SESSION_MAX_LIFETIME, default 168h (7 days); 0 disables.
MaxLifetime time.Duration `env:"MAX_LIFETIME" default:"168h"`
// ExpireOnClose makes the cookie a browser-session cookie, dropped
// when the browser closes (Lifetime still applies). SESSION_EXPIRE_ON_CLOSE.
ExpireOnClose bool `env:"EXPIRE_ON_CLOSE"`
// Domain and Path scope the cookie. SESSION_DOMAIN (default: the
// request's host only) and SESSION_PATH (default "/").
Domain string `env:"DOMAIN"`
Path string `env:"PATH" default:"/"` // see Domain
// Secure sends the cookie over HTTPS only. SESSION_SECURE; the default
// is true, except in the development and testing environments (with
// ForApp).
Secure *bool `env:"SECURE"`
// SameSite is lax, strict or none. SESSION_SAME_SITE, default lax.
// "none" requires Secure.
SameSite string `env:"SAME_SITE" default:"lax"`
// Driver is where sessions are kept: cookie (the whole session in the
// encrypted cookie), database, or a driver passed to ForApp (redis).
// SESSION_DRIVER, default cookie.
Driver string `env:"DRIVER" default:"cookie"`
// Table is the database driver's table. SESSION_TABLE, default
// sessions. Pass the same name to [Migrations].
Table string `env:"TABLE" default:"sessions"`
// Prefix starts the store keys of server-side sessions.
// SESSION_PREFIX, default APP_NAME followed by ":session:".
Prefix string `env:"PREFIX"`
}
Config configures sessions. Environment keys use the SESSION_ prefix; see docs/site/reference/configuration.md.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the configuration used when no SESSION_* variables are set.
func LoadConfig ¶
LoadConfig reads the SESSION_* settings from src.
type Driver ¶ added in v0.2.0
type Driver struct {
// Name is the value of SESSION_DRIVER that selects the driver.
Name string
// Open returns the store for the app.
Open func(app *anetos.App, cfg Config) (cache.Store, error)
}
Driver opens a server-side store for ForApp. The database driver is built in; driver modules provide others (redis.SessionDriver()).
func DatabaseDriver ¶ added in v0.2.0
func DatabaseDriver() Driver
DatabaseDriver keeps sessions in the app's database (SESSION_DRIVER=database), in the table SESSION_TABLE created by Migrations. Call db.Connect before session.ForApp.
type FieldError ¶
type FieldError struct {
Field string `json:"f"` // the form field's name
Message string `json:"m"` // the message to show
}
FieldError is a validation message for one form field.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager loads and saves sessions. Its Middleware method is the session middleware.
func ForApp ¶
ForApp returns a Manager configured from the application's SESSION_* settings and APP_KEY, and provides it as a *session.Manager service. Cookies are Secure by default, except in the development and testing environments. SESSION_DRIVER picks where sessions are kept: cookie and database are built in; pass others, such as redis.SessionDriver(). Server-side sessions use keys starting with SESSION_PREFIX (default APP_NAME and ":session:").
func NewManager ¶
NewManager returns a Manager that stores sessions in cookies encrypted by enc, or with WithStore, in a server-side store.
func (*Manager) CookieName ¶
CookieName returns the name of the session cookie: SESSION_COOKIE, with the "__Host-" prefix when the cookie is Secure, has no Domain and has the Path "/".
func (*Manager) Edit ¶
Edit changes the session r carries (starting one if there is none) without counting as a request: fn sees the session as a handler would (flashed values, Session.Errors, Session.Old), and what was flashed for the next request stays for it, as with Session.Reflash. It returns the session cookie to send with later requests. Tests use it to prepare a session, or to get a CSRF token (s.Token()).
func (*Manager) Load ¶
Load returns the session r carries (an empty one if its cookie is missing, invalid or expired), as the session middleware would give it to the request's handler. Changes to it are not saved. Tests use it to look at the session a response left.
func (*Manager) Middleware ¶
Middleware loads the request's session from its cookie (or starts an empty one), makes it available through From, and saves it in the response's Set-Cookie header when it changed. A new session sets no cookie until something is stored in it. Responses of requests that have a session get "Cache-Control: private" (unless the handler set Cache-Control) and "Vary: Cookie". If the same Manager's middleware already runs for the request, it does nothing.
func (*Manager) Store ¶ added in v0.2.0
Store returns the store of server-side sessions (nil for cookie sessions) and the prefix of their keys.
func (*Manager) Use ¶ added in v0.3.0
Use adds middleware that run inside Manager.Middleware wherever it runs, in order: after the session is loaded, before the route's other middleware. It is for what every page with a session needs, whichever group it is in, such as the signed-in user (make:auth's setupAuth calls sessions.Use(a.Middleware), so the home page's header knows who is signed in). It applies to the routes registered before it and after; call it while setting up the app, before serving. The middleware may run again in a route's group: they must allow that, as auth's and the session's do.
type Option ¶
type Option func(*Manager)
Option configures NewManager.
func WithLogger ¶
WithLogger sets the logger for cookie problems. Default slog.Default().
func WithStore ¶ added in v0.2.0
WithStore keeps sessions in store, under keys starting with prefix ("blog:session:"), instead of in the cookie: the cookie then holds only the encrypted session ID. Any cache store works: the database store, Redis, or the memory store (one process only; sessions end when it stops).
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is one visitor's session. Get it with From. Its methods are safe for concurrent use, but changes made after the response has started are not saved.
func From ¶
From returns the request's session, or nil if the session middleware doesn't run for the request.
func New ¶
func New() *Session
New returns an empty session, for tests. Requests get theirs from the middleware.
func (*Session) Clear ¶
func (s *Session) Clear()
Clear removes every value, flashed ones included. The ID and CSRF token stay.
func (*Session) Errors ¶
func (s *Session) Errors() []FieldError
Errors returns the validation errors flashed by the previous request, in order.
func (*Session) Flash ¶
Flash stores v under key for this request and the next one only: the usual way to show a message after a redirect.
s.Flash("status", "Post saved.")
return c.RedirectRoute("posts.index")
func (*Session) FlashErrors ¶
func (s *Session) FlashErrors(errs ...FieldError)
FlashErrors keeps validation errors for the next request, where Session.Errors returns them. The web package calls it when a form post fails validation.
func (*Session) FlashInput ¶
FlashInput keeps submitted form values for the next request, where Session.OldInput returns them, so a form can be refilled. "_method" and fields whose name contains "password", "secret" or "token" (the CSRF token among them) are left out.
func (*Session) Get ¶
Get decodes the value stored under key into dst (a pointer) and reports whether it was there and decoded.
func (*Session) ID ¶
ID returns the session's random identifier. It changes on Session.Regenerate.
func (*Session) Invalidate ¶
func (s *Session) Invalidate()
Invalidate removes everything and starts a new session: call it when the user logs out. With a server-side store, the old session is removed from it, so no copy of the old cookie works any more. With cookie sessions it clears the session in this browser only: a copy of an earlier cookie stays valid until it expires (SESSION_LIFETIME idle, SESSION_MAX_LIFETIME in all).
func (*Session) Old ¶
Old returns the first value flashed for a form field by the previous request, and whether there was one.
func (*Session) Put ¶
Put stores v under key, encoded as JSON. It panics if v can't be encoded (a channel, a function), which is a programming error.
func (*Session) Reflash ¶
func (s *Session) Reflash()
Reflash keeps every flashed value, errors and input for one more request.
func (*Session) Regenerate ¶
func (s *Session) Regenerate()
Regenerate gives the session a new ID and CSRF token, keeping its values, and restarts its maximum lifetime. Call it when the user logs in, so an identifier or token seen before can't be reused (with a server-side store, the session under the old ID is removed).
func (*Session) RegenerateToken ¶
func (s *Session) RegenerateToken()
RegenerateToken replaces the CSRF token; pages rendered earlier can no longer post.
func (*Session) Token ¶
Token returns the session's CSRF token, creating it on first use, for forms (the "_token" field) and the X-CSRF-Token header. Each call returns a differently masked form of the same token, so pages don't repeat a secret that compression could leak (BREACH).
func (*Session) VerifyToken ¶
VerifyToken reports whether t is a token returned by Session.Token.