From d210966dc3a7501483cf985de3c7b58c24f07220 Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Tue, 30 Dec 2025 23:47:20 -0500 Subject: [PATCH 1/4] feat: allow any HTTP method for /api/auth/envoy and restrict methods for non-envoy proxies --- internal/controller/proxy_controller.go | 16 +++++++++++++-- internal/controller/proxy_controller_test.go | 21 +++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index 40f83748..6c1b3347 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -43,8 +43,8 @@ func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, a func (controller *ProxyController) SetupRoutes() { proxyGroup := controller.router.Group("/auth") - proxyGroup.GET("/:proxy", controller.proxyHandler) - proxyGroup.POST("/:proxy", controller.proxyHandler) + // There is a later check to control allowed methods per proxy + proxyGroup.Any("/:proxy", controller.proxyHandler) } func (controller *ProxyController) proxyHandler(c *gin.Context) { @@ -69,6 +69,18 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { return } + // Only allow GET for non-envoy proxies. + // Envoy uses the original client method for the external auth request + // so we allow Any standard HTTP method for /api/auth/envoy + if req.Proxy != "envoy" && c.Request.Method != http.MethodGet { + log.Warn().Str("method", c.Request.Method).Msg("Invalid method for proxy") + c.JSON(405, gin.H{ + "status": 405, + "message": "Method Not Allowed", + }) + return + } + isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html") if isBrowser { diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 54bb8882..7f3c826a 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -81,6 +81,13 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 400, recorder.Code) + // Test invalid method for non-envoy proxy + recorder = httptest.NewRecorder() + req = httptest.NewRequest("POST", "/api/auth/traefik", nil) + router.ServeHTTP(recorder, req) + + assert.Equal(t, 405, recorder.Code) + // Test logged out user (traefik/caddy) recorder = httptest.NewRecorder() req = httptest.NewRequest("GET", "/api/auth/traefik", nil) @@ -93,7 +100,7 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 307, recorder.Code) assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) - // Test logged out user (envoy) + // Test logged out user (envoy - POST method) recorder = httptest.NewRecorder() req = httptest.NewRequest("POST", "/api/auth/envoy", nil) req.Header.Set("X-Forwarded-Proto", "https") @@ -105,6 +112,18 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 307, recorder.Code) assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) + // Test logged out user (envoy - DELETE method) + recorder = httptest.NewRecorder() + req = httptest.NewRequest("DELETE", "/api/auth/envoy", nil) + req.Header.Set("X-Forwarded-Proto", "https") + req.Header.Set("X-Forwarded-Host", "example.com") + req.Header.Set("X-Forwarded-Uri", "/somepath") + req.Header.Set("Accept", "text/html") + router.ServeHTTP(recorder, req) + + assert.Equal(t, 307, recorder.Code) + assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) + // Test logged out user (nginx) recorder = httptest.NewRecorder() req = httptest.NewRequest("GET", "/api/auth/nginx", nil) From 80dee3d12b6efff46d673462802042ef4df8df5f Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Wed, 31 Dec 2025 00:01:54 -0500 Subject: [PATCH 2/4] feat: add Allow header for invalid methods in proxyHandler --- internal/controller/proxy_controller.go | 1 + internal/controller/proxy_controller_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index 6c1b3347..d6c8bebc 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -74,6 +74,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { // so we allow Any standard HTTP method for /api/auth/envoy if req.Proxy != "envoy" && c.Request.Method != http.MethodGet { log.Warn().Str("method", c.Request.Method).Msg("Invalid method for proxy") + c.Header("Allow", "GET") c.JSON(405, gin.H{ "status": 405, "message": "Method Not Allowed", diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 7f3c826a..4d409a8c 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -87,6 +87,7 @@ func TestProxyHandler(t *testing.T) { router.ServeHTTP(recorder, req) assert.Equal(t, 405, recorder.Code) + assert.Equal(t, "GET", recorder.Header().Get("Allow")) // Test logged out user (traefik/caddy) recorder = httptest.NewRecorder() From f651df112c9ad084c6d334ea1c3a22e3b6be8ca7 Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Sat, 3 Jan 2026 07:11:27 -0500 Subject: [PATCH 3/4] feat: add session max lifetime and fix refresh logic --- .env.example | 4 +- cmd/tinyauth/tinyauth.go | 7 ++-- config.example.yaml | 2 + .../migrations/000004_created_at.down.sql | 1 + .../migrations/000004_created_at.up.sql | 1 + internal/bootstrap/app_bootstrap.go | 4 ++ internal/bootstrap/db_bootstrap.go | 4 ++ internal/bootstrap/service_bootstrap.go | 17 ++++---- internal/config/config.go | 13 +++--- internal/controller/proxy_controller_test.go | 15 +++---- internal/controller/user_controller_test.go | 15 +++---- internal/repository/models.go | 1 + internal/repository/query.sql.go | 14 +++++-- internal/service/auth_service.go | 41 ++++++++++++++----- query.sql | 3 +- schema.sql | 1 + 16 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 internal/assets/migrations/000004_created_at.down.sql create mode 100644 internal/assets/migrations/000004_created_at.up.sql diff --git a/.env.example b/.env.example index 2c6c4fef..65ec3d53 100644 --- a/.env.example +++ b/.env.example @@ -37,7 +37,9 @@ TINYAUTH_USERSFILE="" # Enable secure cookies (requires HTTPS) TINYAUTH_SECURECOOKIE="true" # Session expiry in seconds (7200 = 2 hours) -TINYAUTH_SESSIONEXPIRY="7200" +TINYAUTH_AUTH_SESSIONEXPIRY="7200" +# Session maximum lifetime in seconds (0 = unlimited) +TINYAUTH_AUTH_SESSIONMAXLIFETIME="0" # Login timeout in seconds (300 = 5 minutes) TINYAUTH_LOGINTIMEOUT="300" # Maximum login retries before lockout diff --git a/cmd/tinyauth/tinyauth.go b/cmd/tinyauth/tinyauth.go index 33b40150..7d0dbf76 100644 --- a/cmd/tinyauth/tinyauth.go +++ b/cmd/tinyauth/tinyauth.go @@ -25,9 +25,10 @@ func NewTinyauthCmdConfiguration() *config.Config { Address: "0.0.0.0", }, Auth: config.AuthConfig{ - SessionExpiry: 3600, - LoginTimeout: 300, - LoginMaxRetries: 3, + SessionExpiry: 3600, + SessionMaxLifetime: 0, + LoginTimeout: 300, + LoginMaxRetries: 3, }, UI: config.UIConfig{ Title: "Tinyauth", diff --git a/config.example.yaml b/config.example.yaml index 544bc838..26e56d5e 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -38,6 +38,8 @@ auth: secureCookie: false # Session expiry in seconds (3600 = 1 hour) sessionExpiry: 3600 + # Session maximum lifetime in seconds (0 = unlimited) + sessionMaxLifetime: 0 # Login timeout in seconds (300 = 5 minutes) loginTimeout: 300 # Maximum login retries before lockout diff --git a/internal/assets/migrations/000004_created_at.down.sql b/internal/assets/migrations/000004_created_at.down.sql new file mode 100644 index 00000000..fa7d58a0 --- /dev/null +++ b/internal/assets/migrations/000004_created_at.down.sql @@ -0,0 +1 @@ +ALTER TABLE "sessions" DROP COLUMN "created_at"; diff --git a/internal/assets/migrations/000004_created_at.up.sql b/internal/assets/migrations/000004_created_at.up.sql new file mode 100644 index 00000000..9634b223 --- /dev/null +++ b/internal/assets/migrations/000004_created_at.up.sql @@ -0,0 +1 @@ +ALTER TABLE "sessions" ADD COLUMN "created_at" INTEGER NOT NULL; diff --git a/internal/bootstrap/app_bootstrap.go b/internal/bootstrap/app_bootstrap.go index 5c45f9ce..414beea5 100644 --- a/internal/bootstrap/app_bootstrap.go +++ b/internal/bootstrap/app_bootstrap.go @@ -42,6 +42,10 @@ func NewBootstrapApp(config config.Config) *BootstrapApp { } func (app *BootstrapApp) Setup() error { + // validate session config + if app.config.Auth.SessionMaxLifetime != 0 && app.config.Auth.SessionMaxLifetime < app.config.Auth.SessionExpiry { + return fmt.Errorf("session max lifetime cannot be less than session expiry") + } // Parse users users, err := utils.GetUsers(app.config.Auth.Users, app.config.Auth.UsersFile) diff --git a/internal/bootstrap/db_bootstrap.go b/internal/bootstrap/db_bootstrap.go index ad8f4f6f..ab10daad 100644 --- a/internal/bootstrap/db_bootstrap.go +++ b/internal/bootstrap/db_bootstrap.go @@ -27,6 +27,10 @@ func (app *BootstrapApp) SetupDatabase(databasePath string) (*sql.DB, error) { return nil, fmt.Errorf("failed to open database: %w", err) } + // Limit to 1 connection to sequence writes, this may need to be revisited in the future + // if the sqlite connection starts being a bottleneck + db.SetMaxOpenConns(1) + migrations, err := iofs.New(assets.Migrations, "migrations") if err != nil { diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go index b41fc628..6f6a0883 100644 --- a/internal/bootstrap/service_bootstrap.go +++ b/internal/bootstrap/service_bootstrap.go @@ -58,14 +58,15 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er services.accessControlService = accessControlsService authService := service.NewAuthService(service.AuthServiceConfig{ - Users: app.context.users, - OauthWhitelist: app.config.OAuth.Whitelist, - SessionExpiry: app.config.Auth.SessionExpiry, - SecureCookie: app.config.Auth.SecureCookie, - CookieDomain: app.context.cookieDomain, - LoginTimeout: app.config.Auth.LoginTimeout, - LoginMaxRetries: app.config.Auth.LoginMaxRetries, - SessionCookieName: app.context.sessionCookieName, + Users: app.context.users, + OauthWhitelist: app.config.OAuth.Whitelist, + SessionExpiry: app.config.Auth.SessionExpiry, + SessionMaxLifetime: app.config.Auth.SessionMaxLifetime, + SecureCookie: app.config.Auth.SecureCookie, + CookieDomain: app.context.cookieDomain, + LoginTimeout: app.config.Auth.LoginTimeout, + LoginMaxRetries: app.config.Auth.LoginMaxRetries, + SessionCookieName: app.context.sessionCookieName, }, dockerService, ldapService, queries) err = authService.Init() diff --git a/internal/config/config.go b/internal/config/config.go index b7fe6e39..2e7af668 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -40,12 +40,13 @@ type ServerConfig struct { } type AuthConfig struct { - Users string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"` - UsersFile string `description:"Path to the users file." yaml:"usersFile"` - SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"` - SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"` - LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"` - LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"` + Users string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"` + UsersFile string `description:"Path to the users file." yaml:"usersFile"` + SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"` + SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"` + SessionMaxLifetime int `description:"Maximum session lifetime in seconds." yaml:"sessionMaxLifetime"` + LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"` + LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"` } type OAuthConfig struct { diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 4b6a7e45..5f443826 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -57,13 +57,14 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.", // test }, }, - OauthWhitelist: "", - SessionExpiry: 3600, - SecureCookie: false, - CookieDomain: "localhost", - LoginTimeout: 300, - LoginMaxRetries: 3, - SessionCookieName: "tinyauth-session", + OauthWhitelist: "", + SessionExpiry: 3600, + SessionMaxLifetime: 0, + SecureCookie: false, + CookieDomain: "localhost", + LoginTimeout: 300, + LoginMaxRetries: 3, + SessionCookieName: "tinyauth-session", }, dockerService, nil, queries) // Controller diff --git a/internal/controller/user_controller_test.go b/internal/controller/user_controller_test.go index ff95a3ce..dc8ec5cd 100644 --- a/internal/controller/user_controller_test.go +++ b/internal/controller/user_controller_test.go @@ -60,13 +60,14 @@ func setupUserController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.Eng TotpSecret: totpSecret, }, }, - OauthWhitelist: "", - SessionExpiry: 3600, - SecureCookie: false, - CookieDomain: "localhost", - LoginTimeout: 300, - LoginMaxRetries: 3, - SessionCookieName: "tinyauth-session", + OauthWhitelist: "", + SessionExpiry: 3600, + SessionMaxLifetime: 0, + SecureCookie: false, + CookieDomain: "localhost", + LoginTimeout: 300, + LoginMaxRetries: 3, + SessionCookieName: "tinyauth-session", }, nil, nil, queries) // Controller diff --git a/internal/repository/models.go b/internal/repository/models.go index 0f5195e4..61f7f804 100644 --- a/internal/repository/models.go +++ b/internal/repository/models.go @@ -13,6 +13,7 @@ type Session struct { TotpPending bool OAuthGroups string Expiry int64 + CreatedAt int64 OAuthName string OAuthSub string } diff --git a/internal/repository/query.sql.go b/internal/repository/query.sql.go index 110bd1b9..59248422 100644 --- a/internal/repository/query.sql.go +++ b/internal/repository/query.sql.go @@ -19,12 +19,13 @@ INSERT INTO sessions ( "totp_pending", "oauth_groups", "expiry", + "created_at", "oauth_name", "oauth_sub" ) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) -RETURNING uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, oauth_name, oauth_sub +RETURNING uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, created_at, oauth_name, oauth_sub ` type CreateSessionParams struct { @@ -36,6 +37,7 @@ type CreateSessionParams struct { TotpPending bool OAuthGroups string Expiry int64 + CreatedAt int64 OAuthName string OAuthSub string } @@ -50,6 +52,7 @@ func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (S arg.TotpPending, arg.OAuthGroups, arg.Expiry, + arg.CreatedAt, arg.OAuthName, arg.OAuthSub, ) @@ -63,6 +66,7 @@ func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (S &i.TotpPending, &i.OAuthGroups, &i.Expiry, + &i.CreatedAt, &i.OAuthName, &i.OAuthSub, ) @@ -90,7 +94,7 @@ func (q *Queries) DeleteSession(ctx context.Context, uuid string) error { } const getSession = `-- name: GetSession :one -SELECT uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, oauth_name, oauth_sub FROM "sessions" +SELECT uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, created_at, oauth_name, oauth_sub FROM "sessions" WHERE "uuid" = ? ` @@ -106,6 +110,7 @@ func (q *Queries) GetSession(ctx context.Context, uuid string) (Session, error) &i.TotpPending, &i.OAuthGroups, &i.Expiry, + &i.CreatedAt, &i.OAuthName, &i.OAuthSub, ) @@ -124,7 +129,7 @@ UPDATE "sessions" SET "oauth_name" = ?, "oauth_sub" = ? WHERE "uuid" = ? -RETURNING uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, oauth_name, oauth_sub +RETURNING uuid, username, email, name, provider, totp_pending, oauth_groups, expiry, created_at, oauth_name, oauth_sub ` type UpdateSessionParams struct { @@ -163,6 +168,7 @@ func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) (S &i.TotpPending, &i.OAuthGroups, &i.Expiry, + &i.CreatedAt, &i.OAuthName, &i.OAuthSub, ) diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go index e823e2af..faff1939 100644 --- a/internal/service/auth_service.go +++ b/internal/service/auth_service.go @@ -26,14 +26,15 @@ type LoginAttempt struct { } type AuthServiceConfig struct { - Users []config.User - OauthWhitelist string - SessionExpiry int - SecureCookie bool - CookieDomain string - LoginTimeout int - LoginMaxRetries int - SessionCookieName string + Users []config.User + OauthWhitelist string + SessionExpiry int + SessionMaxLifetime int + SecureCookie bool + CookieDomain string + LoginTimeout int + LoginMaxRetries int + SessionCookieName string } type AuthService struct { @@ -212,6 +213,7 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.Sessio TotpPending: data.TotpPending, OAuthGroups: data.OAuthGroups, Expiry: time.Now().Add(time.Duration(expiry) * time.Second).Unix(), + CreatedAt: time.Now().Unix(), OAuthName: data.OAuthName, OAuthSub: data.OAuthSub, } @@ -242,11 +244,19 @@ func (auth *AuthService) RefreshSessionCookie(c *gin.Context) error { currentTime := time.Now().Unix() - if session.Expiry-currentTime > int64(time.Hour.Seconds()) { + var refreshThreshold int64 + + if auth.config.SessionExpiry <= int(time.Hour.Seconds()) { + refreshThreshold = int64(auth.config.SessionExpiry / 2) + } else { + refreshThreshold = int64(time.Hour.Seconds()) + } + + if session.Expiry-currentTime > refreshThreshold { return nil } - newExpiry := currentTime + int64(time.Hour.Seconds()) + newExpiry := session.Expiry + refreshThreshold _, err = auth.queries.UpdateSession(c, repository.UpdateSessionParams{ Username: session.Username, @@ -265,7 +275,8 @@ func (auth *AuthService) RefreshSessionCookie(c *gin.Context) error { return err } - c.SetCookie(auth.config.SessionCookieName, cookie, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) + c.SetCookie(auth.config.SessionCookieName, cookie, int(newExpiry-currentTime), "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) + log.Trace().Str("username", session.Username).Msg("Session cookie refreshed") return nil } @@ -306,6 +317,14 @@ func (auth *AuthService) GetSessionCookie(c *gin.Context) (config.SessionCookie, currentTime := time.Now().Unix() + if auth.config.SessionMaxLifetime != 0 && currentTime-session.CreatedAt > int64(auth.config.SessionMaxLifetime) { + err = auth.queries.DeleteSession(c, cookie) + if err != nil { + log.Error().Err(err).Msg("Failed to delete session exceeding max lifetime") + } + return config.SessionCookie{}, fmt.Errorf("session expired due to max lifetime exceeded") + } + if currentTime > session.Expiry { err = auth.queries.DeleteSession(c, cookie) if err != nil { diff --git a/query.sql b/query.sql index 36d0e7f9..9fde4e20 100644 --- a/query.sql +++ b/query.sql @@ -8,10 +8,11 @@ INSERT INTO sessions ( "totp_pending", "oauth_groups", "expiry", + "created_at", "oauth_name", "oauth_sub" ) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) RETURNING *; diff --git a/schema.sql b/schema.sql index 42219302..a7f37eb7 100644 --- a/schema.sql +++ b/schema.sql @@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS "sessions" ( "totp_pending" BOOLEAN NOT NULL, "oauth_groups" TEXT NULL, "expiry" INTEGER NOT NULL, + "created_at" INTEGER NOT NULL, "oauth_name" TEXT NULL, "oauth_sub" TEXT NULL ); From c83ce501e1ee3b874ab12ceeece4efd12a774ee4 Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Sat, 3 Jan 2026 07:43:17 -0500 Subject: [PATCH 4/4] fix: set default value for created_at column and improve session expiration logic --- internal/assets/migrations/000004_created_at.up.sql | 2 +- internal/service/auth_service.go | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/assets/migrations/000004_created_at.up.sql b/internal/assets/migrations/000004_created_at.up.sql index 9634b223..a21e944f 100644 --- a/internal/assets/migrations/000004_created_at.up.sql +++ b/internal/assets/migrations/000004_created_at.up.sql @@ -1 +1 @@ -ALTER TABLE "sessions" ADD COLUMN "created_at" INTEGER NOT NULL; +ALTER TABLE "sessions" ADD COLUMN "created_at" INTEGER NOT NULL DEFAULT 0; diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go index faff1939..e71fd5f8 100644 --- a/internal/service/auth_service.go +++ b/internal/service/auth_service.go @@ -317,12 +317,14 @@ func (auth *AuthService) GetSessionCookie(c *gin.Context) (config.SessionCookie, currentTime := time.Now().Unix() - if auth.config.SessionMaxLifetime != 0 && currentTime-session.CreatedAt > int64(auth.config.SessionMaxLifetime) { - err = auth.queries.DeleteSession(c, cookie) - if err != nil { - log.Error().Err(err).Msg("Failed to delete session exceeding max lifetime") + if auth.config.SessionMaxLifetime != 0 && session.CreatedAt != 0 { + if currentTime-session.CreatedAt > int64(auth.config.SessionMaxLifetime) { + err = auth.queries.DeleteSession(c, cookie) + if err != nil { + log.Error().Err(err).Msg("Failed to delete session exceeding max lifetime") + } + return config.SessionCookie{}, fmt.Errorf("session expired due to max lifetime exceeded") } - return config.SessionCookie{}, fmt.Errorf("session expired due to max lifetime exceeded") } if currentTime > session.Expiry {