UI Session Management: RTR, IST, FLST
DRAFT DRAFT DRAFT DRAFT DRAFT
UI Session Management
Session management is complicated. In the simplest case, a person logs in (receiving a token in the form of cookies to start their session), does some work, and logs out (destroying their cookies to end their session). In a less complicated case, a person logs in, does some work, and then their session ends without them explicitly choosing to end it. This could happen for several different reasons:
Refresh Token Rotation (RTR) errors: the UI receives a response from an API request indicating the session is corrupt or compromised.
Idle Session Timeout (IST): a timer in the UI (measuring the time since last activity) has expired.
Fixed-length Session Timeout (FLST): a timer in the UI (measuring the time since authentication) has expired.
While RTR, IST, and FLST feel closely-related because they can all cause a session to end, in fact they are configured and implemented independently.
Under the hood: cookies, tokens, and timers
This section explains the technical implementation of RTR and FLST.
Whether authenticating via Keycloak or directly via an Okapi endpoint, the eventual outcome is that Stripes receives an API response containing token-expiration data in the JSON body and tokens in the accompanying cookies:
an access-token (AT) with a short lifespan (~10 minutes) that is sent along with ordinary API requests (e.g. to retrieve items or PO lines or patron records) and can be used on multiple requests
a refresh token (RT) with a long lifespan (hours to days) that is sent only with refresh API requests to retrieve new tokens and can be used only once
The browser stores the cookies but Stripes does not have access to them. (This is a security measure; their HttpOnly attribute is toggled on, preventing JS from tampering with or even inspecting their content.) Stripes infers their existence by inspecting the JSON portion of the API where the accessTokenExpiration and accessTokenExpiration values align with the cookies' expiration values. The browser shares cookie and FOLIO-session data across all tabs and windows. In a multi-tenant (Enhanced Consortial Services, ECS) environment, this means that switching the tenant in one tab affects all future requests in all other tabs.
RTR is the periodic, background process of renewing the AT. In Ramsons and Sunflower, when Stripes receives the AT/RT cookie pair, it starts a timer that expires 80% of the way through the AT’s lifecycle. When the timer expires, Stripes sends an API request to /authn/refresh; the response contains new tokens that overwrite the old tokens. In Trillium and following releases, Stripes inspects the token-expiration data before making an API request and rotates before making the API request if the token is expired. Additionally, Stripes inspects each response, looking for authentication-related failures. When it detects such a failure, it rotates, and then replays the original request now that the new tokens are in place.
When the AT rotates, its expiration extends forward, creating a "sliding window". In Okapi, the RT's expiration is also calculating on sliding window. In Eureka the RT’s expiration is fixed (thus, FLST). Visually, it looks a bit like this:
// Okapi Sliding window session timeout (SWST)
|---------|---------|---------|---------|
at1-------|
rt1-------------------------------------|
at2-------|
rt2-------------------------------------|
at3-------|
rt3-------------------------------------|
// Eureka fixed length session timeout (FLST)
|---------|---------|---------|---------|
at1-------|
rt1-------------------------------------|
at2-------|
rt2---------------------------|
at3-------|
rt3-----------------|Note that a side-effect of SWST is that a session can be perpetually extended as long as the RT is exchanged before it expires (the length of the window is fixed but the expiration date is perpetually extended). This may be considered a convenience or a security flaw depending on your perspective. FLST tightens security (the endpoint of the session is fixed and the length of the RT window shrinks each time it is refreshed).
From the end-user's point of view, RTR is an invisible, background process under ordinary circumstances. Altering the lifespan of the AT will not have any user-detectable effect. The only time RTR will affect an end-user is if the rotation request itself fails. A rotation failure implies that the cookies are expired or missing or corrupt. Regardless of the cause, on receiving an error response to the rotation request, the UI terminates the session and redirects to /logout.
Configuration
In Okapi, AT and RT expirations are configured on the backend in mod-authtoken. See the mod-authtoken README for details. The AT defaults to 10 minutes. The RT defaults to 7 days.
In Eureka, AT and RT expirations are configured in Keycloak. See RTR Configuration on Eureka for details. Typically, the AT is set to 10 minutes and the RT to 1 day.
Timeouts
When a session begins, Stripes sets two timers:
Idle-Session Timeout: this timer tracks the elapsed time since the last activity (e.g. keyclicks or mouseclicks) and is continually reset with each event.
Fixed-Length-Session Timeout: this timer expires when the RT expires and is reset whenever the RT rotates.
Idle-session timeout
Idle-session timeout is a UI-only feature that tracks browser events and terminates the session if a fixed period of inactivity elapses. Each time the UI receives a new event, it resets the timer, sliding the window forward. Code and configuration for this feature exist exclusively in the UI. When the idle-session timer trips, the UI shows an interactive "Keep working?" modal with a countdown timer. When the timer hits 00:00, the UI will terminate the session and redirect to /logout-timeout. Clicking the "Keep working" button dismisses the modal and resets the timer.
Configuration
IST is configured on the frontend when the UI bundle is built. See stripes.config.js properties for details. The following default values are configurable:
idle session timeout, i.e. how long before an idle session is killed: 4 hours
idle modal timeout, i.e. how long to show the "keep working?" modal: 1 minute
events that are interpreted as activity: keydown, mousedown
Fixed-length-session timeout
Fixed-length-session timeout is implemented in the UI but configured in Keycloak. When the UI receives an RT (i.e., after authentication or after token rotation), it sets a timer to expire when the RT expires, replacing the previous FLST timer. Code for this feature exists in both the UI (to set the UI timer) and the backend (to set the expiration date for the RTs); configuration is in the backend (Okapi uses mod-authtoken and a sliding-window; Eureka uses Keycloak and a fixed-window). When the fixed-length-session timer expires, the UI shows a non-interactive "Session expiration" warning banner with a countdown timer. The banner cannot be dismissed and has no "Keep working?" button because the session cannot be extended. When the timer hits 00:00; the UI will terminate the session and redirect to /logout-timeout.
Configuration
RT expiration is configured on the backend as described above, either in mod-authtoken or in Keycloak. The only aspect of FLST configurable on the frontend is how long the "Session expiration" warning banner is displayed. See stripes.config.js properties for details; the default is 1 minute.
Examples
Okapi, 4h IST, 7d SWST: if a user begins work on Monday at 09:00 and works throughout the day, leaving at 17:00, and returns to work on Tuesday at 08:00, their session will have expired overnight due to IST and they'll have to login again. If they do something interactive every 4h, their session will never expire. This configuration means most users would have to log in once at the beginning of each day and may or may not experience IST during the day. Users will never encounter FLST.
Okapi, 1d IST, 1d SWST: if a user begins work on Monday at 09:00 and works throughout the day, leaving at 17:00, and returns to work on Tuesday at 08:00, their session will have continued through the night. If they do something interactive every 1d, their session will never expire. This configuration means most users would log in once at the beginning of each week, and their sessions would expire over the weekends. Users will never encounter FLST.
Eureka, 4h IST, 1d FLST: if a user begins work on Monday at 09:00 and works throughout the day, leaving at 17:00, and returns to work on Tuesday at 08:00, their session will have expired overnight due to IST and they'll have to login again. This configuration means most users would have to log in once at the beginning of each day and may or may not experience IST during the day. Under ordinary working circumstances, users will never experience FLST with this configuration.
Eureka, 1d IST, 1d FLST: if a user begins work on Monday at 09:00 and works throughout the day, leaving at 17:00, and returns to work on Tuesday at 08:00, their session will have continued through the night. After 1 hour of work, the session will end due to FLST regardless of the user's activity and they will be forced to log in again. This configuration means most users would have to log in once each day, and will interact with FLST on any day when they begin work on FOLIO earlier than when their FOLIO session began on the previous day.