Get Started
Back to Blog

Zero-trust access for real estate compounds — a technical overview

Zero-trust isn't just a buzzword. For gated compounds, it's a concrete architectural pattern: verify every access event cryptographically, log it immutably, and trust no device or network unconditionally.

OT

Omar Taha

Lead Engineer

·March 1, 2026·5 min read

Zero-trust security as a concept was developed for enterprise networks: never assume a request is legitimate because it comes from inside the perimeter. Every request is verified, every action is logged, and no device is permanently trusted.

For physical access control — gates, barriers, turnstiles — the same principles apply. A guard's scanner is not automatically trusted. A QR code is not trusted because it looks right. A network request is not trusted because it comes from the right IP. Everything is verified, every time.

Here's how GateFlow implements zero-trust for physical access.

Layer 1: Cryptographic QR signing

Every QR code generated by GateFlow is signed using HMAC-SHA256. The signature covers the full payload: visitor identity, gate assignment, expiry timestamp, max-uses count, and a unique nonce.

payload = {
  orgId: "org_abc123",
  gateId: "gate_main_north",
  visitorId: "vqr_xyz789",
  issuedAt: 1740854400,
  expiresAt: 1740940800,
  maxUses: 1,
  nonce: "e3b0c44298fc"
}
signature = HMAC-SHA256(JSON.stringify(payload), QR_SIGNING_SECRET)

The scanner app holds the signing secret in its secure local store. Verification happens locally before any network call. A forged or modified QR — including a screenshot of an expired code — fails signature verification in under 5ms.

This means the gate works correctly even when the internet is completely down. The cryptographic verification is offline-capable by design.

Layer 2: Short-lived JWT tokens for scanner auth

Scanner devices authenticate to the API using JWT access tokens with a 15-minute expiry. These tokens are signed with HS256 and contain the scanner's userId, orgId, and role claims.

Token rotation happens on every refresh. If a device is compromised or a guard's session is revoked, the next token refresh fails and the device is locked out — within 15 minutes at most, without any active intervention required.

The scanner role (VISITOR) has the narrowest permission set in the system: it can validate QR codes and read assigned gates. It cannot access QR creation, analytics, resident data, or any admin function. Role-based access control is enforced at every API endpoint.

Layer 3: Offline-encrypted scan queue

When the scanner loses internet connectivity, scans don't fail — they queue locally. The queue is encrypted with AES-256 using a key derived from the device's authentication credentials via PBKDF2.

If a device is stolen while offline, the queue contents are unreadable without the device's active session key. If the session expires while offline, the device cannot decrypt its own queue on restart — a new authentication is required.

When connectivity returns, queued scans sync via a bulk endpoint with Last-Write-Wins conflict resolution. The server deduplicates by scanUuid — each scan event has a UUID assigned at scan time, ensuring that reconnection races never produce duplicate logs.

Layer 4: Immutable audit trail

Every gate event — scan, override, revocation, denial — is written as an append-only ScanLog record. ScanLog rows are never updated or deleted. Soft deletes are used for mutable entities (QR codes, gates, users), but scan events are permanent.

The audit trail records:

  • Timestamp (server-side createdAt)
  • Gate ID and organization ID
  • QR code ID (links to the specific pass)
  • Scanner user ID (which guard)
  • Scan status (SUCCESS, DENIED, EXPIRED, etc.)
  • Device ID
  • Any override notes

This trail is the legal record of who entered your property, when, and on whose authorization. It's what you present to law enforcement, insurance, or a resident dispute. An immutable log is the foundation.

Layer 5: Multi-tenant isolation

GateFlow is a multi-tenant SaaS. Every data model carries an organizationId field. Every API endpoint enforces organizationId scoping — a query that touches Organization A's data cannot, by any code path, return data for Organization B.

This isn't just good practice. It's the threat model. A compromised API key for Organization A gives an attacker exactly the access that key was scoped to — and nothing from any other tenant.

Resident data, scan logs, QR codes, gate configurations, and user records are all partition-isolated at the query layer. Row-level tenant security is enforced in application code, validated by automated tests on every API route.

Layer 6: Watchlists and incident management

Zero-trust doesn't end at the gate. After entry, the system continues to verify. Watchlisted individuals trigger alerts on scan, even if their QR appears valid (a supervisor can revoke and flag simultaneously). Incident reports link to specific scans, creating a chain of evidence.

Supervisor overrides — where a guard admits someone despite a failed scan — are logged with a PIN confirmation and a mandatory reason field. The override appears in the audit trail distinctly, so it's never confused with a normal acceptance.

The compound as a zero-trust boundary

The perimeter of a gated compound is a physical equivalent of a network perimeter. The old model — trust what's inside, verify what comes in once at the gate — fails in exactly the same ways that network perimeter security failed for enterprises.

Zero-trust for compounds means: verify every entry event cryptographically, attribute it to a specific authorization, log it immutably, and never assume that a device or person is trusted because they've been seen before.

GateFlow's architecture implements exactly this model — for every gate, every scan, and every resident — at a cost that compound management can actually afford.

Ready to upgrade your gate access?

Start free with 1 gate and 500 scans/month. No credit card required.

GateFlow Help

Online

Hi! I'm GateFlow's help assistant. How can I help you today?