Skip to Content

Sessions

The session package wraps gorilla/sessions  to provide server-side HTTP session management. It supports two backing stores out of the box — cookie-based (all data signed into the browser cookie) and filesystem-based (data on disk, only the session ID in the cookie) — and exposes simple get/set/destroy helpers on top of the gorilla *sessions.Session object.

Import

import "github.com/gofastadev/gofasta/pkg/session"

Key Types

Store

Store is the package’s main type — a thin wrapper around gorilla/sessions.Store that remembers the session name and exposes convenience methods for reading and writing values.

type Store struct { /* unexported fields */ }

SessionConfig (from pkg/config)

The session configuration lives on config.AppConfig and is loaded from config.yaml or the GOFASTA_SESSION_* environment variables.

type SessionConfig struct { Driver string `koanf:"driver"` // "cookie" or "filesystem" Secret string `koanf:"secret"` // 32 or 64 bytes for HMAC signing SessionName string `koanf:"session_name"` // cookie name FilesystemPath string `koanf:"filesystem_path"` // required when driver=filesystem }

Key Functions

FunctionSignatureDescription
NewCookieStorefunc NewCookieStore(secret, sessionName string) *StoreCreates a cookie-based session store. All session data is serialized into the browser cookie, signed with secret via HMAC.
NewFilesystemStorefunc NewFilesystemStore(path, secret, sessionName string) *StoreCreates a filesystem-based session store. Only the session ID is stored in the cookie; the actual values live on disk under path.

Store Methods

MethodSignatureDescription
Getfunc (s *Store) Get(r *http.Request) (*sessions.Session, error)Returns the gorilla *sessions.Session for the current request.
Savefunc (s *Store) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) errorPersists the session to the response (writes the Set-Cookie header and/or flushes the filesystem file).
SetValuefunc (s *Store) SetValue(r *http.Request, w http.ResponseWriter, key string, value interface{}) errorConvenience helper: fetches the session, writes one key, saves.
GetValuefunc (s *Store) GetValue(r *http.Request, key string) (interface{}, error)Convenience helper: fetches the session and returns the value under key.
Destroyfunc (s *Store) Destroy(r *http.Request, w http.ResponseWriter) errorMarks the session for deletion by setting MaxAge = -1 and saving.

Usage

Creating a Store

Choose one of the two constructors. Both return a *Store you can use from any handler.

import "github.com/gofastadev/gofasta/pkg/session" // Cookie store — simplest, all data lives in the signed cookie. store := session.NewCookieStore( "change-me-in-production-32bytes!", "app_session", ) // Filesystem store — cookie carries only the ID, data lives on disk. store := session.NewFilesystemStore( "./sessions", "change-me-in-production-32bytes!", "app_session", )

Writing Values on Login

func (c *AuthController) Login(w http.ResponseWriter, r *http.Request) error { // ...authenticate the user first... if err := c.store.SetValue(r, w, "user_id", user.ID.String()); err != nil { return apperrors.NewInternal("failed to save session", err) } if err := c.store.SetValue(r, w, "role", user.Role); err != nil { return apperrors.NewInternal("failed to save session", err) } return httputil.OK(w, map[string]string{"status": "logged in"}) }

Reading Values on a Protected Route

func (c *AuthController) Profile(w http.ResponseWriter, r *http.Request) error { userID, err := c.store.GetValue(r, "user_id") if err != nil || userID == nil { return apperrors.NewUnauthorized("not logged in", nil) } user, err := c.service.FindByID(r.Context(), userID.(string)) if err != nil { return err } return httputil.OK(w, user) }

Writing Multiple Values in One Save

For efficiency, fetch the underlying *sessions.Session once, mutate its Values map, then save it manually.

sess, err := c.store.Get(r) if err != nil { return err } sess.Values["user_id"] = user.ID.String() sess.Values["email"] = user.Email sess.Values["role"] = user.Role if err := c.store.Save(r, w, sess); err != nil { return err }

Logout and Session Destruction

func (c *AuthController) Logout(w http.ResponseWriter, r *http.Request) error { if err := c.store.Destroy(r, w); err != nil { return apperrors.NewInternal("failed to destroy session", err) } return httputil.OK(w, map[string]string{"status": "logged out"}) }

Building the Store from Config

Load SessionConfig from config.AppConfig and branch on the driver:

func buildStore(cfg config.SessionConfig) *session.Store { switch cfg.Driver { case "filesystem": return session.NewFilesystemStore(cfg.FilesystemPath, cfg.Secret, cfg.SessionName) default: return session.NewCookieStore(cfg.Secret, cfg.SessionName) } }

Configuration

Add a session: block to your config.yaml:

session: driver: cookie # "cookie" or "filesystem" secret: "change-me-in-production-32bytes!" session_name: app_session filesystem_path: "./sessions" # only used when driver=filesystem

Any field can be overridden via environment variables with the GOFASTA_ prefix:

export GOFASTA_SESSION_DRIVER=filesystem export GOFASTA_SESSION_SECRET="my-secure-secret-32bytes!" export GOFASTA_SESSION_FILESYSTEM_PATH="/var/lib/myapp/sessions"

The pkg/config package’s LoadConfig() populates these fields automatically and provides sane defaults (driver: cookie, session_name: app_session, filesystem_path: ./sessions) when they are missing.

Sessions vs JWT

The session and auth packages cover two different authentication styles:

ConcernSessions (session)JWT (auth)
StateServer-side (cookie or filesystem)Stateless — the token is self-contained
InvalidationDestroy the server-side entryRotate the signing key or maintain a denylist
Cross-origin / mobileHarder — cookies are domain-scopedEasy — clients send Authorization: Bearer …
Best forServer-rendered web apps on one domainREST / GraphQL APIs consumed by SPAs or mobile

A gofasta project can use either, or both, depending on the surface area of the API.

  • Auth — JWT-based authentication for stateless APIs
  • Config — where SessionConfig lives
  • Middleware — wrap your router with logging, CORS, etc.
Last updated on