Overview
You have the option of customizing session handling using two functions: evalMaxLifetimeSE
and evalIdleTimeoutSE
.
Evaluate Max Session Lifetime (
evalMaxLifetimeSE
) determines how sessions reaching their max lifetime are handled. WhilemaxLifetimeSeconds
is still used for individually expiring attributes,evalMaxLifetimeSE
checks if the user has been logged in for too long (beyondMaxTimeout
), and logs them out if so.Evaluate Idle Session Timeout (
evalIdleTimeoutSE
) checks if the user has been inactive for too long and logs them out if so. If this Service Extension is defined, theidleTimeout
value is ignored.
Implementation
Service extensions allow complete flexibility over the process of controlling a user's session lifespan.
To create these service extensions, go to Service Extensions.
From the right sidebar, click the + icon next to Evaluate Max Session Lifetime or Evaluate Idle Session Timeout.
Enter a name and description for the service extension, and click Create.
The service extension code appears on the next page. From here, you can add assets, providers, and/or metadata. When you've finished adding this information, click Update.
You will receive a confirmation message in the lower right corner that the service extension file has been updated.
You can now use this service extension in an existing or new deployment.
Go to the Deployments screen and select an existing deployment from the list or click Create.
Under Orchestrator Settings, next to Session and Cookie, click Edit.
The service extensions you created can be selected from the dropdown menus under Evaluate Session Maximum Lifetime Service Extension and/or Evaluate Session Idle Timeout Service Extension.
Code examples
The example below triggers single logout on a session expiry event. The max session timeout and idle session timeout are determined dynamically depending on the user's employee type (full-time employee vs contractor).
Evaluate Session Maximum Lifetime
package main
import (
"net/http"
"time"
"github.com/strata-io/service-extension/orchestrator"
)
const (
sloEndpoint = "https://example.com/single-logout"
contractorMaxTimeoutSeconds = 3600
fteMaxTimeoutSeconds = 43200
)
// EvalMaxSessionLifetime determines whether a session has reached its max lifetime. The
// expiration check is informed by a whether a user is a full-time employee or
// contractor.
func EvalMaxSessionLifetime(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
createdAt time.Time,
) bool {
logger := api.Logger()
sess, err := api.Session()
if err != nil {
logger.Error(
"se", "failed to retrieve session",
"err", err,
)
return false
}
employeeType, err := sess.GetString("okta.employeeType")
if err != nil {
logger.Error(
"se", "failed to retrieve 'employeeType'",
"err", err,
)
return false
}
maxTimeout := contractorMaxTimeoutSeconds
if employeeType == "full_time" {
maxTimeout = fteMaxTimeoutSeconds
}
if sessionExpired(createdAt, maxTimeout) {
logger.Info(
"se", "user has reached max session lifetime: redirecting to SLO endpoint")
http.Redirect(rw, req, sloEndpoint, http.StatusFound)
// False is returned here so that the SLO endpoint is aware which IDPs to log
// the user out of. If true is returned, all session attributes including the
// list of authenticated IDPs will be cleared.
return false
}
return false
}
func sessionExpired(startPoint time.Time, timeout int) bool {
return startPoint.Before(time.Now().Add(-time.Duration(timeout) * time.Second))
}
Evaluate Session Idle Timeout
package main
import (
"net/http"
"time"
"github.com/strata-io/service-extension/orchestrator"
)
const (
sloEndpoint = "https://example.com/single-logout"
contractorIdleTimeoutSeconds = 300
fteIdleTimeoutSeconds = 3600
)
// EvalIdleSessionTimeout determines whether a session has reached its idle timeout. The
// expiration check is informed by a whether a user is a full-time employee or
// contractor.
func EvalIdleSessionTimeout(
api orchestrator.Orchestrator,
rw http.ResponseWriter,
req *http.Request,
lastAccess time.Time,
) bool {
logger := api.Logger()
sess, err := api.Session()
if err != nil {
logger.Error(
"se", "failed to retrieve session",
"err", err,
)
return false
}
employeeType, err := sess.GetString("okta.employeeType")
if err != nil {
logger.Error(
"se", "failed to retrieve 'employeeType'",
"err", err,
)
return false
}
idleTimeout := contractorIdleTimeoutSeconds
if employeeType == "full_time" {
idleTimeout = fteIdleTimeoutSeconds
}
if sessionExpired(lastAccess, idleTimeout) {
logger.Info("se", "user has reached idle session lifetime: redirecting to SLO endpoint")
http.Redirect(rw, req, sloEndpoint, http.StatusFound)
// False is returned here so that the SLO endpoint is aware which IDPs to log
// the user out of. If true is returned, all session attributes including the
// list of authenticated IDPs will be cleared.
return false
}
return false
}
func sessionExpired(startPoint time.Time, timeout int) bool {
return startPoint.Before(time.Now().Add(-time.Duration(timeout) * time.Second))
}