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:
+19
-11
@@ -18,6 +18,16 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"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 {
|
type AuthHandler struct {
|
||||||
db *database.Queries
|
db *database.Queries
|
||||||
jwtKey []byte
|
jwtKey []byte
|
||||||
@@ -219,8 +229,8 @@ func (h *AuthHandler) Register(c echo.Context) error {
|
|||||||
Value: accessToken,
|
Value: accessToken,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Secure: false,
|
Secure: false, // TODO: Set to true in production with HTTPS
|
||||||
MaxAge: 3600,
|
MaxAge: SessionDurationSec,
|
||||||
}
|
}
|
||||||
c.SetCookie(cookie)
|
c.SetCookie(cookie)
|
||||||
|
|
||||||
@@ -238,9 +248,8 @@ func (h *AuthHandler) Register(c echo.Context) error {
|
|||||||
localStorage.setItem('token', '%s');
|
localStorage.setItem('token', '%s');
|
||||||
localStorage.setItem('refreshToken', '%s');
|
localStorage.setItem('refreshToken', '%s');
|
||||||
localStorage.setItem('user', JSON.stringify(%s));
|
localStorage.setItem('user', JSON.stringify(%s));
|
||||||
document.cookie = 'token=%s; path=/; max-age=3600';
|
|
||||||
window.location.href = '/dashboard';
|
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)
|
return c.HTML(http.StatusCreated, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +263,7 @@ window.location.href = '/dashboard';
|
|||||||
Token: accessToken,
|
Token: accessToken,
|
||||||
RefreshToken: refreshToken,
|
RefreshToken: refreshToken,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
ExpiresIn: 3600,
|
ExpiresIn: SessionDurationSec,
|
||||||
User: UserProfile{
|
User: UserProfile{
|
||||||
ID: uuid.UUID(user.ID.Bytes).String(),
|
ID: uuid.UUID(user.ID.Bytes).String(),
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
@@ -365,8 +374,8 @@ func (h *AuthHandler) Login(c echo.Context) error {
|
|||||||
Value: accessToken,
|
Value: accessToken,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Secure: false,
|
Secure: false, // TODO: Set to true in production with HTTPS
|
||||||
MaxAge: 3600,
|
MaxAge: SessionDurationSec,
|
||||||
}
|
}
|
||||||
c.SetCookie(cookie)
|
c.SetCookie(cookie)
|
||||||
|
|
||||||
@@ -388,9 +397,8 @@ func (h *AuthHandler) Login(c echo.Context) error {
|
|||||||
localStorage.setItem('token', '%s');
|
localStorage.setItem('token', '%s');
|
||||||
localStorage.setItem('refreshToken', '%s');
|
localStorage.setItem('refreshToken', '%s');
|
||||||
localStorage.setItem('user', JSON.stringify(%s));
|
localStorage.setItem('user', JSON.stringify(%s));
|
||||||
document.cookie = 'token=%s; path=/; max-age=3600';
|
|
||||||
window.location.href = '%s';
|
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)
|
return c.HTML(http.StatusOK, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +414,7 @@ window.location.href = '%s';
|
|||||||
Token: accessToken,
|
Token: accessToken,
|
||||||
RefreshToken: refreshToken,
|
RefreshToken: refreshToken,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
ExpiresIn: 3600,
|
ExpiresIn: SessionDurationSec,
|
||||||
User: UserProfile{
|
User: UserProfile{
|
||||||
ID: uuid.UUID(user.ID.Bytes).String(),
|
ID: uuid.UUID(user.ID.Bytes).String(),
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
@@ -780,7 +788,7 @@ func (h *AuthHandler) generateJWTWithAllClaims(userID, userRole, userEmail, user
|
|||||||
"user_role": userRole,
|
"user_role": userRole,
|
||||||
"user_email": userEmail,
|
"user_email": userEmail,
|
||||||
"user_username": userUsername,
|
"user_username": userUsername,
|
||||||
"exp": time.Now().Add(1 * time.Hour).Unix(),
|
"exp": time.Now().Add(SessionDuration).Unix(),
|
||||||
"iat": time.Now().Unix(),
|
"iat": time.Now().Unix(),
|
||||||
}
|
}
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func (h *AuthHandler) RefreshAccessToken(c echo.Context) error {
|
|||||||
return c.JSON(http.StatusOK, RefreshTokenResponse{
|
return c.JSON(http.StatusOK, RefreshTokenResponse{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
ExpiresIn: 3600,
|
ExpiresIn: SessionDurationSec,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user