Skip to main content

Lock Screen

After a configurable period of inactivity the application overlays a full-screen lock screen. The user must re-enter their password to continue. The session (JWT) remains valid — the lock is enforced client-side and backed by a server-side password check.


How it works

User inactive for N minutes


lockScreen() dispatched
isLocked = true in Redux


<LockScreen /> overlay renders (z-index 9999, backdrop blur)

user enters password


POST /api/auth/password/verify

┌────┴────┐
204 401
│ │
unlock show error,
screen clear field

Configuration

The inactivity timeout is driven by the ui.lock.timeout_minutes config key.

PropertyValue
Config keyui.lock.timeout_minutes
Typeint
Default15 minutes
Range1 – 480 minutes
Allowed levelsGlobal + Tenant (bitmask 3)

A TenantAdmin can override the timeout for their organisation:

POST /api/config/tenant/set
{ "code": "ui.lock.timeout_minutes", "value": "30" }

The resolved value arrives in the login config map and is persisted in localStorage under the key hr_lock_timeout_minutes so it survives a page refresh.


Redux state — lockSlice

File: src/reduxToolkit/reducers/layout/lockSlice.ts

State fieldTypeDescription
isLockedbooleantrue while the lock screen is shown
timeoutMinutesnumberInactivity threshold; initialised from localStorage

Actions

ActionDescription
lockScreen()Activates the lock screen
unlockScreen()Dismisses the lock screen after a successful password check
setLockTimeout(n)Updates the timeout and persists it to localStorage

Inactivity hook — useLockScreen

File: src/hooks/useLockScreen.ts

Registers window-level event listeners and resets a setTimeout on every interaction. When the timer fires, it dispatches lockScreen().

Monitored events: mousemove, mousedown, keydown, touchstart, scroll, click.

The hook is a no-op when isAuthenticated === false or isLocked === true, so it never runs before login or while already locked.

Usage — called once at the top of Layout:

// src/layout/index.tsx
useLockScreen();

Lock screen component — <LockScreen />

File: src/auth/LockScreen.tsx

Rendered inside Layout whenever isLocked === true:

{isLocked && <LockScreen />}

Features

  • Fixed full-screen overlay with backdrop blur (blur(6px)) and a semi-transparent dark background.
  • Shows the logged-in user's avatar, full name, and email address.
  • Password field with show/hide toggle.
  • Submit calls authService.verifyPassword(password)POST /api/auth/password/verify.
    • On 204: dispatches unlockScreen().
    • On 401: shows the lockScreen.errorWrongPassword i18n message and clears the field.
  • "Not you?" button dispatches logout() and redirects to /login.

i18n keys

All visible strings use the lockScreen.* namespace. Add translations for every supported locale.

KeyEnglish value
lockScreen.titleSession locked. Enter your password to continue.
lockScreen.passwordPassword
lockScreen.unlockUnlock
lockScreen.unlockingVerifying...
lockScreen.errorWrongPasswordIncorrect password. Please try again.
lockScreen.notYouNot you? Sign in with a different account

Changing the timeout at runtime

Call setLockTimeout from any component or settings page:

import { setLockTimeout } from "../reduxToolkit/reducers/layout/lockSlice";

dispatch(setLockTimeout(30)); // 30 minutes

This updates both the Redux state and localStorage. The change takes effect on the next timer reset (i.e., after the next user interaction).