diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 12db564..6d1f731 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -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'; -`, accessToken, refreshToken, fmt.Sprintf(`{"id":"%s","email":"%s","username":"%s"}`, uuid.UUID(user.ID.Bytes).String(), user.Email, user.Username), accessToken) +`, 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'; -`, 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) +`, 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) diff --git a/internal/handlers/refresh_token.go b/internal/handlers/refresh_token.go index d9da78d..4f44b5e 100644 --- a/internal/handlers/refresh_token.go +++ b/internal/handlers/refresh_token.go @@ -71,7 +71,7 @@ func (h *AuthHandler) RefreshAccessToken(c echo.Context) error { return c.JSON(http.StatusOK, RefreshTokenResponse{ AccessToken: accessToken, TokenType: "Bearer", - ExpiresIn: 3600, + ExpiresIn: SessionDurationSec, }) }