Skip to content

Commit

Permalink
Encode auth token expiry in cookie max age
Browse files Browse the repository at this point in the history
Cookies without a max age (or expiry date) become session cookies, which
means they are cleared when the browser is closed. Most browsers,
however, support session restore, which is where sessions are not
cleared on browser close, appearing 'restored' when the browser is
opened again.

For browsers which do not support session restore, particularly mobile
Firefox and Chrome, users get logged out every time they close their
browser - which is not a pleasant experience.

Setting the max age of cookies the same as the expiry date on the auth
token makes them persistent until the specified date, so users will only
be logged out when their token expires (as intended).
  • Loading branch information
Aleksbgbg committed Jan 27, 2024
1 parent 4d4ad45 commit 0661d71
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 9 deletions.
7 changes: 4 additions & 3 deletions backend/controllers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package controllers
import (
"net/http"
"streamfox-backend/models"
"time"

"github.com/gin-gonic/gin"
)

const AUTHORIZATION_COOKIE = "Authorization"

func setAuthCookie(c *gin.Context, token string) {
c.SetCookie(AUTHORIZATION_COOKIE, token, 0, "", "", false, false)
func setAuthCookie(c *gin.Context, token string, expiry time.Time) {
c.SetCookie(AUTHORIZATION_COOKIE, token, int(time.Until(expiry).Seconds()), "", "", false, false)
}

func authenticate(c *gin.Context, user *models.User) error {
Expand All @@ -20,7 +21,7 @@ func authenticate(c *gin.Context, user *models.User) error {
return err
}

setAuthCookie(c, token)
setAuthCookie(c, token.value, token.expiry)
return nil
}

Expand Down
22 changes: 16 additions & 6 deletions backend/controllers/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,23 @@ func SetupApiSecret() error {
return nil
}

func generateToken(userId models.Id) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
jwtKeyUserId: userId.String(),
jwtKeyExpiration: time.Now().
Add(time.Hour * time.Duration(config.Values.AppTokenLifespanHrs)).
Unix(),
type token struct {
value string
expiry time.Time
}

func generateToken(userId models.Id) (*token, error) {
expiry := time.Now().Add(time.Hour * time.Duration(config.Values.AppTokenLifespanHrs))

value, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
jwtKeyUserId: userId.String(),
jwtKeyExpiration: expiry.Unix(),
}).SignedString(apiSecret)
if err != nil {
return nil, err
}

return &token{value, expiry}, nil
}

func getClaim[T any](claims jwt.MapClaims, key string) (T, error) {
Expand Down

0 comments on commit 0661d71

Please sign in to comment.