feat(auth): extend session duration to 7 days using constants

- Add SessionDuration constant (7 days) and SessionDurationSec computed value
- Update JWT token expiration to use SessionDuration instead of 1 hour
- Update register/login cookie MaxAge to use SessionDurationSec (604800)
- Update register/login API response ExpiresIn to use SessionDurationSec
- Update refresh token endpoint ExpiresIn to use SessionDurationSec
- Remove redundant client-side document.cookie lines from login/register
- Add TODO comment for HTTPS cookie Secure flag

This provides Google-like persistent sessions with a single source of truth
for session duration, eliminating hardcoded values throughout the codebase.
This commit is contained in:
2026-02-16 16:49:43 -05:00
parent c9ebc5b11a
commit 2e1af8d20b
2 changed files with 20 additions and 12 deletions
+19 -11
View File
@@ -18,6 +18,16 @@ import (
"golang.org/x/crypto/bcrypt"
)
const (
// Session duration constants
// Follows same pattern as refresh_token.go
SessionDuration = 7 * 24 * time.Hour // 7 days
)
// SessionDurationSec is the session duration in seconds for use in cookies and API responses
// Note: This is computed from SessionDuration to avoid magic numbers
var SessionDurationSec = int(SessionDuration.Seconds())
type AuthHandler struct {
db *database.Queries
jwtKey []byte
@@ -219,8 +229,8 @@ func (h *AuthHandler) Register(c echo.Context) error {
Value: accessToken,
Path: "/",
HttpOnly: true,
Secure: false,
MaxAge: 3600,
Secure: false, // TODO: Set to true in production with HTTPS
MaxAge: SessionDurationSec,
}
c.SetCookie(cookie)
@@ -238,9 +248,8 @@ func (h *AuthHandler) Register(c echo.Context) error {
localStorage.setItem('token', '%s');
localStorage.setItem('refreshToken', '%s');
localStorage.setItem('user', JSON.stringify(%s));
document.cookie = 'token=%s; path=/; max-age=3600';
window.location.href = '/dashboard';
</script>`, accessToken, refreshToken, fmt.Sprintf(`{"id":"%s","email":"%s","username":"%s"}`, uuid.UUID(user.ID.Bytes).String(), user.Email, user.Username), accessToken)
</script>`, accessToken, refreshToken, fmt.Sprintf(`{"id":"%s","email":"%s","username":"%s"}`, uuid.UUID(user.ID.Bytes).String(), user.Email, user.Username))
return c.HTML(http.StatusCreated, html)
}
@@ -254,7 +263,7 @@ window.location.href = '/dashboard';
Token: accessToken,
RefreshToken: refreshToken,
TokenType: "Bearer",
ExpiresIn: 3600,
ExpiresIn: SessionDurationSec,
User: UserProfile{
ID: uuid.UUID(user.ID.Bytes).String(),
Email: user.Email,
@@ -365,8 +374,8 @@ func (h *AuthHandler) Login(c echo.Context) error {
Value: accessToken,
Path: "/",
HttpOnly: true,
Secure: false,
MaxAge: 3600,
Secure: false, // TODO: Set to true in production with HTTPS
MaxAge: SessionDurationSec,
}
c.SetCookie(cookie)
@@ -388,9 +397,8 @@ func (h *AuthHandler) Login(c echo.Context) error {
localStorage.setItem('token', '%s');
localStorage.setItem('refreshToken', '%s');
localStorage.setItem('user', JSON.stringify(%s));
document.cookie = 'token=%s; path=/; max-age=3600';
window.location.href = '%s';
</script>`, accessToken, refreshToken, fmt.Sprintf(`{"id":"%s","email":"%s","username":"%s","first_name":"%s","last_name":"%s"}`, uuid.UUID(user.ID.Bytes).String(), user.Email, user.Username, user.FirstName.String, user.LastName.String), accessToken, redirect)
</script>`, accessToken, refreshToken, fmt.Sprintf(`{"id":"%s","email":"%s","username":"%s","first_name":"%s","last_name":"%s"}`, uuid.UUID(user.ID.Bytes).String(), user.Email, user.Username, user.FirstName.String, user.LastName.String), redirect)
return c.HTML(http.StatusOK, html)
}
@@ -406,7 +414,7 @@ window.location.href = '%s';
Token: accessToken,
RefreshToken: refreshToken,
TokenType: "Bearer",
ExpiresIn: 3600,
ExpiresIn: SessionDurationSec,
User: UserProfile{
ID: uuid.UUID(user.ID.Bytes).String(),
Email: user.Email,
@@ -780,7 +788,7 @@ func (h *AuthHandler) generateJWTWithAllClaims(userID, userRole, userEmail, user
"user_role": userRole,
"user_email": userEmail,
"user_username": userUsername,
"exp": time.Now().Add(1 * time.Hour).Unix(),
"exp": time.Now().Add(SessionDuration).Unix(),
"iat": time.Now().Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)