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
| Policy | What it does | When to pick it |
|---|---|---|
| Permissive | No 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 devices | Every 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 required | Every 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.
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.
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:
- User (or their owner) emails hello@opticops.in from the email address registered against their account.
- 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).
- 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.
What this protects against (and what it doesn't)
| Threat | Permissive | Trusted devices | Passkey 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.