Setup · access control

Secure access.

Per-org device gate. Off by default — flip it on when your team is ready. Passkey-first (Touch ID / Face ID / Windows Hello), with a trusted-device fallback for browsers that don't support WebAuthn.

Why a device gate at all

Sign-in cookies are convenient and easy to steal. A staffer who quits with their browser cookies still cached, a phone left on a train, a competitor walking behind your counter — these are the real Indian-retail data leak vectors. The default permissive mode is fine for small chains; for any org where customer PII matters, flipping the policy gives you instant revocation and cryptographically-strong device binding.

The three policies

PolicyWhat it doesWhen to pick it
PermissiveNo device gate. Anyone with a valid sign-in cookie can access from anywhere.Default for new orgs. Single-shop, low-stakes data, no compliance pressure.
Trusted devicesEvery new device must be approved by an owner. Cookie + browser fingerprint identifies the device. Revoke kills access immediately.You want to know which devices have access and be able to revoke. Moderate friction (one approval per device).
Passkey requiredEvery approved device must register a passkey (Touch ID / Face ID / Windows Hello). User taps fingerprint at session start.You want bank-grade access control. Falls back to trusted-device on browsers without WebAuthn support.

How to flip the policy

Owner / regional manager only. /settings/security. Pick a radio, hit Save.

Flipping to Passkey required needs you to first register a passkey on the device you're currently using. The form blocks the save until you do — otherwise the next page-load would lock you out of your own org. Visit /auth/device-setup, register, come back, flip.

What the user sees

First sign-in after policy goes live

Normal sign-in (magic link or Google), then lands on /auth/device-setup. Two buttons:

  • 🔑 Set up with passkey — browser prompts Touch ID / Face ID; key gets generated inside the secure enclave.
  • Use trusted-device fallback — auto-selected if the browser doesn't support WebAuthn. Just registers a cookie+fingerprint device row.

After registration, the user lands on /auth/awaiting-approval until the owner approves. Owners get an email notification with a deep-link to the approval row.

Sign-ins after approval

Under passkey-required, every fresh JWT session starts with a one-tap passkey check on /auth/passkey-verify. Browser refreshes within the JWT lifetime don't re-prompt. Under trusted-devices the user goes straight in.

Revoked devices

On the user's next request, they land on /auth/device-revoked with a Sign out button. No exfiltration window — revocation is checked at every page load, not just at sign-in.

Approving + revoking

Owner / regional manager goes to /settings/security sees three sections:

  • Pending approval — amber-bordered. Click Approve.
  • Approved devices — labelled (auto-named, rename anytime), with last-seen timestamp + IP. Per-row Revoke.
  • Revoked — historical record. Cannot un-revoke; the user re-registers a fresh device if they need access again.
Every approve / revoke / rename / policy change writes to audit_log with the actor, target user, and timestamp. Visible to any owner / regional manager / auditor.

Recovery

A user who loses their only registered device cannot self-recover. By design — self-serve recovery is the weakest link in any device-bound flow (SIM swaps, social engineering).

The flow is white-glove:

  1. User (or their owner) emails hello@opticops.in from the email address registered against their account.
  2. We verify identity out-of-band — typically a call to the owner's phone on file, plus knowledge of the org's structure (branches, recent orders).
  3. We mark their existing device as revoked and ask them to sign in fresh on the new device, which routes them through standard device setup again.
We never bypass the device gate from the inside — even the platform-admin path goes through the same audit log. No quiet backdoor for “trusted” users.

What this protects against (and what it doesn't)

ThreatPermissiveTrusted devicesPasskey required
Stolen sign-in cookie❌ wins✅ blocked (fingerprint mismatch)✅ blocked
Stolen cookie + fingerprint cookie both❌ wins🟡 partial — works until admin revokes✅ blocked (no passkey)
Lost / stolen phone with app open❌ wins✅ admin revokes → access dies✅ admin revokes → access dies
Walked-up-to logged-in counter❌ wins❌ wins❌ wins (need OS auto-lock)
Phishing → user enters credentials on fake page❌ wins✅ attacker can't register a device✅ blocked
Server-side database dump❌ wins🟡 partial — needs cookie too✅ blocked (private keys never on server)
Compromised employee with valid passkey🟡 audit log🟡 audit log🟡 audit log + admin revoke

Honest caveats

  • Passkeys need iOS 16+ / Android 9+ / modern Chrome / Safari / Edge. Older browsers fall back to trusted-device (which is still better than permissive).
  • Cookie+fingerprint isn't cryptographic. An attacker who steals both gets in until admin revokes. Passkey path closes this.
  • Shared device (one iPad, five staff) works fine — each user registers their own passkey on the same iPad. Touch ID / Face ID disambiguates by user.
  • Recovery friction is by design. Self-serve recovery would defeat the whole point. Email us, we verify, we reset.

Next up

Platform admin

For the Opticops team running recovery + emergency revocation flows.