Cookies, CookieParser & ClearCookie
Cookies are essential for session management, user preferences, and tracking. Learn how to set, read, configure, and clear cookies in Go Fiber — including secure cookie options, cookie-based authentication patterns, and common cookie pitfalls that compromise security.
Cookies are small pieces of data stored in the user's browser and sent with every request to your server. They power: session management (keeping users logged in), user preferences (theme, language, display settings), tracking (analytics, personalization), and CSRF protection (same-site cookie validation). Fiber makes working with cookies simple — but the security configuration is critical to get right.
Setting Cookies
Basic Cookie
app.Get("/set-cookie", func(c *fiber.Ctx) error {
// Simple cookie — name and value
c.Cookie(&fiber.Cookie{
Name: "username",
Value: "johndoe",
})
return c.SendString("Cookie set!")
})
Cookie with Full Configuration
app.Post("/login", func(c *fiber.Ctx) error {
// ... authenticate user ...
// Set a secure session cookie
c.Cookie(&fiber.Cookie{
Name: "session_token",
Value: generateSessionToken(),
Path: "/", // Available on all paths
Domain: "", // Current domain only
MaxAge: 86400 * 7, // 7 days in seconds
Expires: time.Now().Add(7 * 24 * time.Hour),
Secure: true, // HTTPS only
HTTPOnly: true, // Not accessible via JavaScript
SameSite: "Lax", // CSRF protection
})
return c.JSON(fiber.Map{
"message": "Login successful",
})
})
Let's break down each option:
- Name — The cookie identifier (e.g., "session_token")
- Value — The cookie data (keep it short — cookies have a 4KB limit)
- Path — Which paths receive this cookie. "/" means all paths. "/admin" means only /admin/* paths
- Domain — Which domain receives the cookie. Empty = current domain. ".example.com" = all subdomains
- MaxAge — Lifetime in seconds. 0 = session cookie (deleted when browser closes). -1 = delete immediately
- Expires — Absolute expiration time. MaxAge takes precedence if both are set
- Secure — Cookie only sent over HTTPS. Always true in production
- HTTPOnly — Not accessible via JavaScript (document.cookie). Prevents XSS-based cookie theft
- SameSite — "Strict" (never sent cross-site), "Lax" (sent on top-level navigation), "None" (always sent, requires Secure)
Reading Cookies
// Read a single cookie
app.Get("/profile", func(c *fiber.Ctx) error {
// Get cookie value
username := c.Cookies("username")
if username == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "Not logged in",
})
}
return c.JSON(fiber.Map{
"message": "Welcome back, " + username,
})
})
// Read cookie with a default value
app.Get("/settings", func(c *fiber.Ctx) error {
// If "theme" cookie doesn't exist, default to "light"
theme := c.Cookies("theme", "light")
language := c.Cookies("language", "en")
return c.JSON(fiber.Map{
"theme": theme,
"language": language,
})
})
Practical Cookie Patterns
User Preferences
// Save user preferences
app.Post("/preferences", func(c *fiber.Ctx) error {
type Preferences struct {
Theme string `json:"theme"`
Language string `json:"language"`
PageSize int `json:"page_size"`
}
var prefs Preferences
if err := c.BodyParser(&prefs); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid request body",
})
}
// Set each preference as a cookie
cookieConfig := fiber.Cookie{
Path: "/",
MaxAge: 86400 * 365, // 1 year
HTTPOnly: false, // Allow JS access for UI theming
SameSite: "Lax",
}
cookieConfig.Name = "theme"
cookieConfig.Value = prefs.Theme
c.Cookie(&cookieConfig)
cookieConfig.Name = "language"
cookieConfig.Value = prefs.Language
c.Cookie(&cookieConfig)
cookieConfig.Name = "page_size"
cookieConfig.Value = fmt.Sprintf("%d", prefs.PageSize)
c.Cookie(&cookieConfig)
return c.JSON(fiber.Map{
"message": "Preferences saved",
})
})
// Apply preferences via middleware
func PreferencesMiddleware(c *fiber.Ctx) error {
// Make preferences available to all handlers
c.Locals("theme", c.Cookies("theme", "light"))
c.Locals("language", c.Cookies("language", "en"))
pageSize := 20 // default
if ps := c.Cookies("page_size"); ps != "" {
if parsed, err := strconv.Atoi(ps); err == nil {
pageSize = parsed
}
}
c.Locals("page_size", pageSize)
return c.Next()
}
Remember Me Login
app.Post("/login", func(c *fiber.Ctx) error {
type LoginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
RememberMe bool `json:"remember_me"`
}
var req LoginRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid request",
})
}
// ... validate credentials ...
// Session duration based on "remember me"
maxAge := 86400 // 1 day default
if req.RememberMe {
maxAge = 86400 * 30 // 30 days
}
sessionToken := generateSecureToken()
c.Cookie(&fiber.Cookie{
Name: "session",
Value: sessionToken,
Path: "/",
MaxAge: maxAge,
Secure: true,
HTTPOnly: true,
SameSite: "Lax",
})
return c.JSON(fiber.Map{
"message": "Login successful",
})
})
Clearing Cookies
// Clear a specific cookie
app.Post("/logout", func(c *fiber.Ctx) error {
// Method 1: ClearCookie with name
c.ClearCookie("session")
c.ClearCookie("username")
return c.JSON(fiber.Map{
"message": "Logged out successfully",
})
})
// Clear cookie with specific path/domain
// ClearCookie only works if path and domain match the original cookie
app.Post("/logout", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "session",
Value: "", // Empty value
Path: "/", // Must match original cookie path
MaxAge: -1, // Expire immediately
Secure: true,
HTTPOnly: true,
SameSite: "Lax",
})
return c.JSON(fiber.Map{
"message": "Logged out successfully",
})
})
// Clear ALL cookies
app.Post("/clear-all", func(c *fiber.Ctx) error {
c.ClearCookie() // No arguments = clear all cookies
return c.JSON(fiber.Map{
"message": "All cookies cleared",
})
})
Important: ClearCookie() sets the cookie's expiration to the past, which tells the browser to delete it. The cookie's Path and Domain must match the original cookie — if they don't, the browser won't delete it.
Cookie-Based Auth Middleware
func AuthMiddleware(c *fiber.Ctx) error {
sessionToken := c.Cookies("session")
if sessionToken == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "Authentication required",
})
}
// Validate the session token
user, err := validateSession(sessionToken)
if err != nil {
// Invalid or expired session — clear the cookie
c.ClearCookie("session")
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "Session expired — please login again",
})
}
// Store user in locals for downstream handlers
c.Locals("user", user)
return c.Next()
}
// Apply to protected routes
func SetupRoutes(app *fiber.App) {
// Public routes
app.Post("/login", loginHandler)
app.Post("/register", registerHandler)
// Protected routes
protected := app.Group("/api", AuthMiddleware)
protected.Get("/profile", getProfile)
protected.Put("/profile", updateProfile)
protected.Post("/logout", logout)
}
Security Best Practices
- Always set HTTPOnly for session cookies — prevents JavaScript access (XSS attacks can't steal the session)
- Always set Secure in production — cookies only transmitted over HTTPS
- Use SameSite=Lax or Strict — prevents CSRF attacks by restricting when cookies are sent cross-site
- Don't store sensitive data in cookies — store only a session ID, keep actual data server-side (Redis/database)
- Set reasonable expiration — session cookies (no MaxAge) for sensitive apps, 7-30 days for "remember me"
- Use cryptographic session tokens — 32+ bytes of random data, generated with crypto/rand
- Rotate session tokens — issue a new token after login, privilege escalation, or periodically
What's Next
You now know how to work with cookies in Fiber — setting, reading, configuring security options, and clearing them. In the next tutorial, we'll explore URL parameters and query strings — extracting, validating, and using them to build filterable, sortable API endpoints.