session

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func Migrations added in v0.2.0

func Migrations(table string) *migrate.Set

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

func NewContext(ctx context.Context, s *Session) context.Context

NewContext returns ctx carrying s. The middleware does this; tests can use it to call handlers with a session.

func Value

func Value[T any](s *Session, key string) (T, bool)

Value returns the value stored under key as a T, and whether it was there and decoded:

userID, ok := session.Value[int64](s, "user_id")

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

func LoadConfig(src config.Source) (Config, error)

LoadConfig reads the SESSION_* settings from src.

func (Config) Validate

func (c Config) Validate() error

Validate implements config.Validator.

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

func ForApp(app *anetos.App, drivers ...Driver) (*Manager, error)

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

func NewManager(cfg Config, enc *encryption.Encrypter, opts ...Option) (*Manager, error)

NewManager returns a Manager that stores sessions in cookies encrypted by enc, or with WithStore, in a server-side store.

func (*Manager) Config

func (m *Manager) Config() Config

Config returns the manager's configuration.

func (*Manager) CookieName

func (m *Manager) CookieName() string

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

func (m *Manager) Edit(r *http.Request, fn func(s *Session)) (*http.Cookie, error)

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

func (m *Manager) Load(r *http.Request) *Session

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

func (m *Manager) Middleware(next http.Handler) http.Handler

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

func (m *Manager) Store() (cache.Store, string)

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

func (m *Manager) Use(mw ...func(http.Handler) http.Handler)

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

func WithLogger(l *slog.Logger) Option

WithLogger sets the logger for cookie problems. Default slog.Default().

func WithStore added in v0.2.0

func WithStore(store cache.Store, prefix string) Option

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

func From(ctx context.Context) *Session

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) Delete

func (s *Session) Delete(key string)

Delete removes key.

func (*Session) Errors

func (s *Session) Errors() []FieldError

Errors returns the validation errors flashed by the previous request, in order.

func (*Session) Flash

func (s *Session) Flash(key string, v any)

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

func (s *Session) FlashInput(values url.Values)

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

func (s *Session) Get(key string, dst any) bool

Get decodes the value stored under key into dst (a pointer) and reports whether it was there and decoded.

func (*Session) Has

func (s *Session) Has(key string) bool

Has reports whether key is set.

func (*Session) ID

func (s *Session) ID() string

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) Keep

func (s *Session) Keep(keys ...string)

Keep keeps the given flashed values for one more request.

func (*Session) Old

func (s *Session) Old(field string) (string, bool)

Old returns the first value flashed for a form field by the previous request, and whether there was one.

func (*Session) OldInput

func (s *Session) OldInput() url.Values

OldInput returns the form values flashed by the previous request.

func (*Session) Pull

func (s *Session) Pull(key string, dst any) bool

Pull decodes the value under key into dst and removes it.

func (*Session) Put

func (s *Session) Put(key string, v any)

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) String

func (s *Session) String(key string) string

String returns the string stored under key, or "".

func (*Session) Token

func (s *Session) Token() string

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

func (s *Session) VerifyToken(t string) bool

VerifyToken reports whether t is a token returned by Session.Token.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL