Skip to content

Commit

Permalink
Feature: Session Only Cookies (#1752)
Browse files Browse the repository at this point in the history
* feat(ctx): add SessionOnly property on Cookie struct

* feat(middleware/config): add CookieSessionOnly property on middleware Config struct

* feat(csrf): link config CookieSessionOnly with fiber.Cookie in create middleware function

* fix(ctx_test): add tests for SessionOnly cookie in test_ctx_cookie

* fix(readme): update readme in csrf middleware for CookieSessionOnly property

* remove deprecated property from CookieSessionOnly explaination comments
  • Loading branch information
abhi12299 committed Feb 7, 2022
1 parent ad1a925 commit 68fcd8c
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 26 deletions.
28 changes: 17 additions & 11 deletions ctx.go
Expand Up @@ -75,15 +75,16 @@ type Range struct {

// Cookie data for c.Cookie
type Cookie struct {
Name string `json:"name"`
Value string `json:"value"`
Path string `json:"path"`
Domain string `json:"domain"`
MaxAge int `json:"max_age"`
Expires time.Time `json:"expires"`
Secure bool `json:"secure"`
HTTPOnly bool `json:"http_only"`
SameSite string `json:"same_site"`
Name string `json:"name"`
Value string `json:"value"`
Path string `json:"path"`
Domain string `json:"domain"`
MaxAge int `json:"max_age"`
Expires time.Time `json:"expires"`
Secure bool `json:"secure"`
HTTPOnly bool `json:"http_only"`
SameSite string `json:"same_site"`
SessionOnly bool `json:"session_only"`
}

// Views is the interface that wraps the Render function.
Expand Down Expand Up @@ -410,8 +411,13 @@ func (c *Ctx) Cookie(cookie *Cookie) {
fcookie.SetValue(cookie.Value)
fcookie.SetPath(cookie.Path)
fcookie.SetDomain(cookie.Domain)
fcookie.SetMaxAge(cookie.MaxAge)
fcookie.SetExpire(cookie.Expires)
// only set max age and expiry when SessionOnly is false
// i.e. cookie supposed to last beyond browser session
// refer: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_the_lifetime_of_a_cookie
if !cookie.SessionOnly {
fcookie.SetMaxAge(cookie.MaxAge)
fcookie.SetExpire(cookie.Expires)
}
fcookie.SetSecure(cookie.Secure)
fcookie.SetHTTPOnly(cookie.HTTPOnly)

Expand Down
8 changes: 8 additions & 0 deletions ctx_test.go
Expand Up @@ -660,6 +660,14 @@ func Test_Ctx_Cookie(t *testing.T) {
cookie.SameSite = CookieSameSiteNoneMode
c.Cookie(cookie)
utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))

expect = "username=john; path=/; secure; SameSite=None"
// should remove expires and max-age headers
cookie.SessionOnly = true
cookie.Expires = expire
cookie.MaxAge = 10000
c.Cookie(cookie)
utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
}

// go test -v -run=^$ -bench=Benchmark_Ctx_Cookie -benchmem -count=4
Expand Down
4 changes: 4 additions & 0 deletions middleware/csrf/README.md
Expand Up @@ -109,6 +109,10 @@ type Config struct {
// Optional. Default value "Lax".
CookieSameSite string

// Decides whether cookie should last for only the browser sesison.
// Ignores Expiration if set to true
CookieSessionOnly bool

// Expiration is the duration before csrf token will expire
//
// Optional. Default: 1 * time.Hour
Expand Down
4 changes: 4 additions & 0 deletions middleware/csrf/config.go
Expand Up @@ -53,6 +53,10 @@ type Config struct {
// Optional. Default value "Lax".
CookieSameSite string

// Decides whether cookie should last for only the browser sesison.
// Ignores Expiration if set to true
CookieSessionOnly bool

// Expiration is the duration before csrf token will expire
//
// Optional. Default: 1 * time.Hour
Expand Down
32 changes: 17 additions & 15 deletions middleware/csrf/csrf.go
Expand Up @@ -48,13 +48,14 @@ func New(config ...Config) fiber.Handler {
if manager.getRaw(token) == nil {
// Expire cookie
c.Cookie(&fiber.Cookie{
Name: cfg.CookieName,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
Expires: time.Now().Add(-1 * time.Minute),
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
Name: cfg.CookieName,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
Expires: time.Now().Add(-1 * time.Minute),
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
SessionOnly: cfg.CookieSessionOnly,
})
return cfg.ErrorHandler(c, errTokenNotFound)
}
Expand All @@ -71,14 +72,15 @@ func New(config ...Config) fiber.Handler {

// Create cookie to pass token to client
cookie := &fiber.Cookie{
Name: cfg.CookieName,
Value: token,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
Expires: time.Now().Add(cfg.Expiration),
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
Name: cfg.CookieName,
Value: token,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
Expires: time.Now().Add(cfg.Expiration),
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
SessionOnly: cfg.CookieSessionOnly,
}
// Set cookie to response
c.Cookie(cookie)
Expand Down

0 comments on commit 68fcd8c

Please sign in to comment.