> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# App Lock: PIN, biometric, and session lock

> Set an app PIN, enable biometric unlock, and configure inactivity and background session lock for the staff app from your Security settings.

App Lock places a no-PHI lock screen in front of the authenticated app whenever you background the tab or stay idle past your inactivity timeout. You unlock with a 6-digit PIN, a platform biometric, or by signing in again — no patient information is shown until you do.

## Overview

App Lock is a client-side surface in the authenticated shell. When the lock engages, an overlay covers route content in place — there is no separate `/lock` route. Your session, navigation state, and unsaved work in memory are preserved. Lock state, the PIN-derived key, and your local policy are stored in `sessionStorage` only and are cleared when the tab closes. Lock and unlock events are written to the audit log without PHI.

App Lock applies to the staff app at `/settings/security`. Portal patients manage MFA on their own [Security Settings](/pf/security-settings) page.

## Who it's for

Any signed-in staff user. There is no permission gate — every user can configure their own App Lock policy and PIN. Organization admins can also enforce lock-on-mobile and a maximum inactivity timeout. When that policy is set, the enforced values override your local preferences.

## Before you start

* Sign in to the staff app.
* For biometric unlock, use a browser and device that support WebAuthn platform authenticators (Touch ID, Face ID, Windows Hello, Android biometrics).
* Review the in-app notice: the PIN-derived key is stored in `sessionStorage` for the current tab only. It is defense-in-depth and does not satisfy HIPAA encryption-at-rest on its own.

## Steps

<Steps>
  <Step title="Open Security settings">
    Go to **Settings → Security** (`/settings/security`). The **App Lock** section appears alongside MFA settings.
  </Step>

  <Step title="Set an app PIN">
    Select **Set PIN**, enter a 6-digit numeric PIN, and confirm it. The app derives a PBKDF2 key from your PIN and stores only the derived value — the raw PIN is never sent to the server.
  </Step>

  <Step title="Choose when to lock">
    Turn on **Lock when app is backgrounded** to engage the lock as soon as the tab loses visibility. Set **Inactivity timeout** to the number of minutes of no interaction before the app locks.
  </Step>

  <Step title="Enable biometric unlock (optional)">
    Select **Use biometric to unlock** and complete the platform biometric prompt to enroll. The option only appears on supported devices. Raw biometric data never leaves the device.
  </Step>

  <Step title="Verify the lock">
    Switch tabs or wait out the inactivity timeout. The lock screen should appear with no PHI visible. Unlock with your PIN, biometric, or **Sign in again**.
  </Step>
</Steps>

## Unlocking

The lock screen offers three actions, depending on what you have configured and what the device supports:

* **Enter PIN** — Type your 6-digit PIN. After **5 incorrect attempts**, PIN entry is paused for **30 seconds**. After **3 lockout cycles in the same session**, the app escalates to a full sign-in.
* **Use biometric** — Shown when biometric unlock is enabled and supported. On failure or when biometric is unavailable, fall back to PIN entry or full sign-in.
* **Sign in again** / **Lock and sign out** — Clears the Supabase session and returns you to the login screen. Use this on shared or unattended devices.

In a PWA context where WebAuthn is unavailable and PHI access is required, the lock screen only offers **Sign in again** — PIN-only unlock is not allowed in that mode.

## Organization policy

Org admins can enforce App Lock for mobile clients through Platform settings:

| Setting                    | Effect                                                                                                  |
| -------------------------- | ------------------------------------------------------------------------------------------------------- |
| `require_app_lock_mobile`  | When `true`, mobile clients must engage App Lock regardless of the user's local preference.             |
| `app_lock_timeout_minutes` | Sets the maximum inactivity timeout. The client uses the lower of this value and the user's preference. |

When policy is enforced, the relevant controls on **Settings → Security** display the enforced value and cannot be relaxed.

## Audit events

App Lock writes the following fire-and-forget audit events (no PHI):

* `app_locked`, `app_unlocked`
* `app_pin_failed_attempt`, `app_pin_lockout`
* `app_biometric_enrolled`, `app_biometric_disabled`
* `app_biometric_unlock_success`, `app_biometric_unlock_failed`

Review them in [Audit logs](/pf/audit-logs) or [Security events](/pf/security-events).

## Example: enforce a 5-minute mobile lock

An admin sets the org policy so every mobile session locks after 5 minutes of inactivity, even if a user prefers a longer timeout:

```json theme={null}
{
  "module": "platform.auth",
  "settings": {
    "require_app_lock_mobile": true,
    "app_lock_timeout_minutes": 5
  }
}
```

After the policy syncs, mobile clients show the enforced 5-minute timeout in **Settings → Security** and lock at that interval regardless of the user's local preference.

## Key concepts

**Lock trigger** — The condition that engages the overlay. Two triggers ship today: the Page Visibility API (background/foreground transitions) and an inactivity timer driven by user input events.

**PIN-derived key** — A PBKDF2-derived value stored in `sessionStorage`. Used for constant-time PIN verification on the device. The raw PIN is never persisted or transmitted.

**Escalation to full re-login** — After repeated PIN lockouts in the same session, the app forces a Supabase sign-out and returns the user to the login screen.

**No-PHI lock screen** — The overlay never renders patient identifiers, route content, or cached data. On any internal error, the lock fails secure (stays locked).

## Related

<Columns cols={2}>
  <Card title="Security Settings (portal)" icon="shield-halved" href="/pf/security-settings">
    Patient portal MFA management.
  </Card>

  <Card title="Sessions & Devices" icon="monitor" href="/pf/sessions-devices">
    Review active sessions and trusted devices.
  </Card>

  <Card title="Security events" icon="bell" href="/pf/security-events">
    Audit-backed security event feed.
  </Card>

  <Card title="Audit logs" icon="clipboard-list" href="/pf/audit-logs">
    Full audit log with lock/unlock events.
  </Card>
</Columns>

<Note>
  This page documents shipped product behavior. It is not medical, legal, or
  billing advice. Verify against your organization's policies and applicable
  regulations before using it for clinical, compliance, or billing decisions.
  Protected health information (PHI) shown in the product is governed by your
  tenant's access controls and is never exposed in this documentation.
</Note>

<Accordion title="Documentation sources">
  * src/platform/auth/app-lock/AppLockContext.tsx
  * src/platform/auth/app-lock/AppLockGate.tsx
  * src/platform/auth/app-lock/LockScreenOverlay.tsx
  * src/platform/auth/app-lock/PinSetupDialog.tsx
  * src/platform/auth/app-lock/AppLockSettingsSection.tsx
  * src/platform/auth/app-lock/useAppLockState.ts
  * src/platform/auth/app-lock/useVisibilityAndInactivityLockTrigger.ts
  * src/platform/auth/app-lock/biometric-utils.ts
  * src/platform/auth/app-lock/pin-utils.ts
  * src/platform/settings/SecuritySettingsPage.tsx
</Accordion>
