Skip to content

Risk-based step-up: conditionally require biometrics before approving/rejecting a notification #384

Description

@abroa01

Summary

Introduce a policy gate so the app decides — based on the notification type and the client type — whether to require a biometric check (Face ID / Touch ID / fingerprint) before the user approves or rejects a push notification.

This is a risk-based / step-up authentication pattern:

  • High-risk notifications (e.g. sudo / privileged escalation) → always require biometrics.
  • Routine login approvals from a trusted client → allow one-tap, no biometric.
  • Reject actions → likely never require biometrics (rejecting is the safe action).

Motivation

Today every approve/reject is a single tap regardless of risk. Some actions are high-impact and should require proof of presence/identity, while forcing biometrics on every routine approval hurts UX. A configurable policy keyed on notification type + client type gives the right balance.

Current code touchpoints

  • notificationType exists but is hardcoded server-sideserver/main.js (~line 723) sets notificationType: "approval". The /send-notification handler only destructures username, title, body, actions, apikey, client_id and currently ignores deviceType, restriction, and metaData that callers already send (see send_notification.sh, client/WebNotificationPage.jsx). The type (and a "client type") would need to be threaded: request body → FCM data payload → notification history record.
  • Two approve/reject choke points must both enforce the gate (otherwise the tray path bypasses it):
    • In-app modal: sendUserAction in client/mobile/src/ui/hooks/useNotificationHandler.js (~L147-181)
    • Notification tray buttons: handleActionFromTray in client/mobile/push-notifications.js (~L142-165)
  • Biometric primitive already available: window.Fingerprint.loadBiometricSecret is already used at login (client/mobile/src/ui/Login.jsx ~L94-120) and can be reused as a "verify identity" step before calling notifications.handleResponse.

Proposed flow

flowchart TD
    A[User taps Approve/Reject] --> B{Policy check:\nnotificationType + clientType + action}
    B -->|requires biometric| C[Fingerprint.loadBiometricSecret]
    C -->|success| D[notifications.handleResponse]
    C -->|fail/cancel| E[Abort, show error]
    B -->|no biometric needed| D
    D --> F[Update status]
Loading

Open decisions (not yet decided — to be resolved on this ticket)

  1. Policy location: client-side vs server-aware.

    • Client-side only is simpler but bypassable by a tampered client.
    • Server-aware would record/verify that a biometric was performed, making it a hard security control rather than just a UX gate.
    • Status: undecided.
  2. Source of "client type".

    • Could derive from existing client_id / API key clientId.
    • Or add a new explicit field to the /send-notification payload.
    • Need a taxonomy (e.g. trusted internal vs. third-party) that maps to a policy.
    • Status: undecided.
  3. Which notification types require biometrics.

    • e.g. sudo / privileged escalation vs. routine login.
    • Need the concrete list and the default behavior for unknown types.
    • Status: undecided.

Acceptance criteria (draft, pending decisions above)

  • Notification type and client type are propagated end-to-end (request → FCM payload → history record).
  • A configurable policy maps (notificationType, clientType, action) → biometric required yes/no.
  • Biometric gate enforced in both the in-app modal and the notification-tray action paths.
  • Biometric failure/cancel aborts the action with clear feedback; no silent approval.
  • (If server-aware is chosen) the server records/verifies biometric step-up.

Notes

Created to track the idea and capture the open design decisions before implementation. No code changes yet.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions