Building Neighbourlink: Fine-Grained Disaster Response Authorization with AWS Cedar and Serverless Architecture
**Neighbourlink** is a map-based platform for hazard awareness and community response. It combines local hazard updates, experimental flood-risk estimates, and user reports with photos. Residents can corroborate reports, share corrections, and request help through SOS. Street/Satellite maps, 2D/3D views, live location, light/dark themes, and a mobile-friendly interface make local information accessible. It supports help coordination without replacing official emergency services.
Introduction: The High-Stakes Nature of Crisis Coordination
When monsoons submerge urban corridors or seismic tremors rupture infrastructure, seconds determine outcomes. In emergency disaster response, software ceases to be a luxury—it becomes frontline infrastructure.
Over the past months, we designed and built Neighbourlink , an open community hazard awareness and crisis coordination platform. Neighbourlink provides real-time flood simulation, geo-targeted hazard tracking, crowdsourced incident reporting, and emergency SOS broadcasting.
However, building software for civilian safety introduces a profound security and privacy dilemma:
- Civilian Privacy vs. Responder Operational Readiness: When a resident is trapped by rising floodwaters and issues an emergency SOS, the platform captures their exact GPS coordinates, cell phone number, and household status. If this sensitive data is exposed to everyone, bad actors could exploit stranded civilians. But if it is gated behind complex friction, first responders cannot reach them in time.
- Crowdsource Integrity vs. Misinformation Abuse: Community corroboration accelerates disaster verification. Yet, rogue actors or panicked users might self-corroborate fake reports or reopen closed disaster events.
In traditional architectures, developers tackle this with nested
if/else checks and role-based access control (RBAC) scattered across API endpoints. But in high-stress, evolving crisis systems, hardcoded permissions lead to security drift, subtle privilege leaks, and untestable rules.To solve this, we decoupled our entire authorization layer using AWS Cedar—AWS’s open-source, expressive, and formally verifiable policy language. In this article, I will walk you through how we integrated AWS Cedar via WebAssembly into a modern Next.js serverless architecture, backed by AWS cloud services and PostgreSQL.
What Users Get — The Neighbourlink Feature Suite
Before diving into policies and code, let’s explore what users experience when they open Neighbourlink on their phones or laptops.
plaintext
+-----------------------------------------------------------------------------------+| NEIGHBOURLINK PLATFORM |+-----------------------------------------------------------------------------------+| [ Command Map ] [ Live Hazards ] [ Flood Risk ] [ SOS Help ] || - 3D Perspective Tilt - USGS Quakes - 24h Rain Fall - 1-Tap SOS || - Snap-Style Avatars - GDACS Cyclones - Soil Saturation - Fuzzed Map || - Basemap Switcher - Air Quality (NAQI) - Honest "No-Data" - Rescue GPS |+-----------------------------------------------------------------------------------+| [ Citizen Reporting ] [ Community Verification ] [ Responder Station ] || - Photo Evidence - Independent Corroboration - Boat / Medical Dispatch || - Category Pins - Dispute Resolution - Callback & Status Track |+-----------------------------------------------------------------------------------+
1. Geospatial Command Center with 3D Walkers & Snap-Style Avatars
- Dynamic 2D / 3D Perspective Tilt: Users can toggle between flat orthographic 2D maps and an immersive 55° tilted 3D perspective with real-time compass bearing and pitch controls.
- Snap-Style Presence Avatars: Inspired by Snapchat’s Snap Map, users and emergency volunteers appear with customizable dynamic avatars and animated 3D pedestrian walkers, showing real-time community activity across streets and wards.
- Seamless Basemap Switching: Toggle effortlessly between high-contrast light mode (CARTO Positron), night rescue dark mode (CARTO Dark Matter), MapTiler vector tiles, and Esri Satellite imagery—all without camera jitter, marker drops, or reloads.
- Global & Local Geocoded Search: Instant fuzzy search allows users to fly their camera directly to specific neighborhoods, wards, landmarks, or international regions.
2. Live Multi-Source Disaster Telemetry
Neighbourlink aggregates real-time environmental data from global and regional observation networks:
- Seismic Telemetry (USGS): Ingests live earthquake occurrences with magnitude, depth, coordinates, and epicenter distance calculations.
- Global Disaster Alerts (GDACS): Surfaces tropical cyclones, tsunamis, volcanic activity, and river flood warnings with severity badges (Advisory, Warning, Critical).
- Hyperlocal Weather & Air Quality (Open-Meteo): Displays live temperature, precipitation rates, wind speeds, and the India National Air Quality Index (NAQI) with PM2.5 and PM10 breakdown.
3. Transparent Flood-Risk Simulator (No False Safety)
Floods are the most common and devastating urban hazard. Neighbourlink includes an experimental rule-based flood risk engine:
- Multi-Factor Analysis: Computes localized flood susceptibility using elevation contours, 24-hour recent precipitation, forecast rain volumes, historical soil saturation, and local drainage capacity.
- The "Honest Data" Guarantee: Most disaster apps fabricate a "Low Risk" green badge when data is missing. Neighbourlink enforces a strict rule: if required meteorological sensors or forecast inputs are unavailable, the system displays
INSUFFICIENT DATA, preventing false senses of security.
4. Crowdsourced Hazard Reporting with Photo Evidence
- Pinpoint Incident Pinning: Citizens can report localized hazards in seconds (e.g., Severe Waterlogging, Road Cave-in / Landslide, Fallen Powerlines / Trees, Storm Debris).
- Tamper-Checked Evidence Uploads: Users attach camera photos with metadata validation. Photos are assigned unique incident tracking codes (e.g.,
INC-2026-0042).
- Impact Categorization: Reports include affected transit modes (vehicles stalling, footpaths submerged, power outage).
5. Anti-Abuse Community Corroboration & Dispute Management
A major risk in community-driven emergency apps is rumor propagation and panic. Neighbourlink introduces an independent verification pipeline:
- Community Corroboration: When nearby residents encounter a reported hazard, they can click "I Also Observed This". Once independent observations meet the threshold, the pin automatically upgrades from UNVERIFIED (Amber) to COMMUNITY-CORROBORATED (Blue).
- Strict Anti-Self-Verification: Users are strictly blocked from voting on or corroborating their own reports.
- Dispute & Resolution Tracking: If a drain clears or a hazard is resolved, residents can submit a dispute ("Water drained after municipal pumps turned on"). The pin transitions to RESOLVED, retaining an auditable history rather than vanishing silently.
6. Emergency SOS Dispatch with Privacy-Preserving Fuzzing
When disaster strikes and lives are in jeopardy, civilians need an immediate lifeline:
- One-Tap SOS Broadcast: Civilians can broadcast emergency requests across four critical categories: Trapped in Floodwaters, Medical Emergency, Evacuation Assistance, or Essential Supplies.
- The Dual-Tier Privacy Protection Model:
- Public Civilian View: To safeguard vulnerable victims from bad actors or looters, the public map displays only a soft ~1km fuzzed radius circle (
fuzzyLatitude,fuzzyLongitude). Contact numbers are completely redacted on the server.
- Verified Responder View: Authorized disaster rescue units (e.g., SDRF, local rescue NGOs) and platform administrators receive the unredacted, pinpoint GPS coordinates, household headcount, and the direct callback telephone number.
- Live Operation Pipeline: Responders acknowledge requests ("Boat Unit 3 dispatched"), publish progress updates, and mark cases resolved once citizens are confirmed safe.
- Call 112 Hotline Shortcut: Built-in mobile quick-dial shortcuts to National Emergency response numbers.
7. Area Watch Subscriptions & Push Notifications
- Neighborhood Watchlists: Users can subscribe to specific wards or neighborhood radiuses (e.g., 5km around their residence or elderly relatives' homes).
- Notification Popover & In-App Alert Center: Real-time bell alerts notify residents when official warnings are published, an SOS is triggered nearby, or an observed hazard status changes.
The Architectural Blueprint
Before diving into policies, here is how Neighbourlink is structured across the stack:
plaintext
+-------------------------------+| Next.js 16 (App Router SSR) || Deployed on AWS / Serverless |+---------------+---------------+|+-------------------------+-------------------------+| | |v v v+-----------------+ +-----------------+ +-----------------+| AWS Cedar Engine| | Amazon Cognito | | Amazon S3 || (@cedar-policy | | (User Pools & | | (Presigned URL || cedar-wasm) | | Role Groups) | | Private Evidence|+-----------------+ +-----------------+ +-----------------+| | |+-------------------------+-------------------------+|v+---------------------------------+| PostgreSQL Database (Supabase) || Session & Transaction Poolers |+---------------------------------+
Key Pillars:
- Authorization Engine: AWS Cedar (
@cedar-policy/cedar-wasm/nodejs) evaluating zero-trust policies in sub-millisecond in-memory WASM execution.
- Identity & Authentication: Amazon Cognito / Supabase Auth with Google OAuth 2.0 federation and encrypted session tokens.
- Evidence Storage: Amazon S3 private storage using short-lived presigned PUT/GET URLs for disaster photo evidence.
- Database Layer: Managed PostgreSQL using PgBouncer connection pooling for serverless resilience.
Why AWS Cedar?
Cedar (the foundation behind Amazon Verified Permissions) is purpose-built for fine-grained authorization. Unlike general-purpose languages, Cedar has three characteristics that make it ideal for humanitarian and mission-critical systems:
- Default Deny: If no policy explicitly permits an action, Cedar denies access automatically.
- Explicit Forbid Wins: A single
forbidstatement immediately supersedes any number ofpermitstatements. This makes enforcing anti-abuse boundaries bulletproof.
- Decoupled & Audit-Ready: Policies are written in clean human-readable syntax that non-engineering auditors can review without reading application source code.
Writing Crisis Authorization Policies in Cedar
In Neighbourlink, we defined three primary entity types:
- Principals:
User::"<id>"with attributes{ role: "RESIDENT" | "RESPONDER" | "ADMIN" | "GUEST" }
- Resources:
-
SOSRequest::"<id>"with attributes{ requester: User }
-
Incident::"<id>"with attributes{ reporter: User, status: String }
-
Platform::"neighbourlink"
- Actions:
ViewExactLocation,AcknowledgeSOS,PostSOSUpdate,ResolveSOS,CorroborateIncident,PublishOfficialHazard
Here is our live Cedar policy set (
src/authz/policies.ts ):plaintext
// 1. SOS Privacy: Responders and Admins see exact GPS and telephonepermit (principal,action == Action::"ViewExactLocation",resource is SOSRequest)when { principal.role == "RESPONDER" || principal.role == "ADMIN" };// 2. Requester Self-Access: Citizens always see their own SOS requestpermit (principal,action == Action::"ViewExactLocation",resource is SOSRequest)when { resource.requester == principal };// 3. Dispatch Operations: Only verified units can acknowledge and updatepermit (principal,action in [Action::"AcknowledgeSOS", Action::"PostSOSUpdate"],resource is SOSRequest)when { principal.role == "RESPONDER" || principal.role == "ADMIN" };// 4. Resolution: Responders, Admins, or the Requester themselves can mark safepermit (principal,action == Action::"ResolveSOS",resource is SOSRequest)when {principal.role == "RESPONDER" ||principal.role == "ADMIN" ||resource.requester == principal};// 5. Community Verification: Independent residents can corroborate hazardspermit (principal,action == Action::"CorroborateIncident",resource is Incident);// 6. Anti-Abuse Rule: No self-corroborationforbid (principal,action == Action::"CorroborateIncident",resource is Incident)when { resource.reporter == principal };// 7. Lifecycle Integrity: Resolved incidents cannot be corroboratedforbid (principal,action == Action::"CorroborateIncident",resource is Incident)when { resource.status == "RESOLVED" };// 8. Official Warnings: Only Admins can publish regional hazardspermit (principal,action == Action::"PublishOfficialHazard",resource == Platform::"neighbourlink")when { principal.role == "ADMIN" };
Notice how clean the anti-abuse rules are. Rule #6 (
no-self-corroboration ) forbids a user from verifying their own report, regardless of what permission rule #5 allows.
Executing Cedar in Next.js Serverless via WebAssembly
Rather than making high-latency network round-trips to an external authorization service for every single map point and coordinate, we packaged the AWS Cedar evaluation engine directly into our Next.js backend using
@cedar-policy/cedar-wasm .Here is our authorization adapter (
src/authz/cedar.ts ):plaintext
import { isAuthorized, type CedarValueJson, type EntityJson } from "@cedar-policy/cedar-wasm/nodejs";import { POLICIES } from "./policies";export type Role = "RESIDENT" | "RESPONDER" | "ADMIN" | "GUEST";export interface Principal {id: string;role: Role;}export type AuthzResource =| { type: "SOSRequest"; id: string; requesterId: string }| { type: "Incident"; id: string; reporterId: string; status: string }| { type: "Platform" };export interface AuthzDecision {allowed: boolean;reasons: string[];}export function authorize(principal: Principal,action: AuthzAction,resource: AuthzResource): AuthzDecision {const res = resourceEntity(resource);const entities: EntityJson[] = [{ uid: { type: "User", id: principal.id }, attrs: { role: principal.role }, parents: [] },{ uid: res.uid, attrs: res.attrs, parents: [] },];const answer = isAuthorized({principal: { type: "User", id: principal.id },action: { type: "Action", id: action },resource: res.uid,context: {},policies: { staticPolicies: POLICIES },entities,});if (answer.type === "failure") {console.error("Cedar authorization failed:", answer.errors.map((e) => e.message));return { allowed: false, reasons: [] };}const { decision, diagnostics } = answer.response;return {allowed: decision === "allow",reasons: diagnostics.reason};}
Next.js 16 Configuration for WASM
In
next.config.ts , we ensure Turbopack and the Node server treat @cedar-policy/cedar-wasm as an external server package so the underlying .wasm binary loads smoothly from disk in serverless runtime:plaintext
import type { NextConfig } from "next";const nextConfig: NextConfig = {serverExternalPackages: ["@cedar-policy/cedar-wasm"],turbopack: true,};export default nextConfig;
Putting It Together: Dual-Tier Privacy Redaction
With Cedar in place, our API routes enforce a strict dual-tier data model:
plaintext
export class SOSService {static async getSOSRequestsForViewer(currentUserId?: string) {const viewerRole = await this.resolveViewerRole(currentUserId);const viewer = { id: currentUserId ?? "anonymous", role: viewerRole };const records = await prisma.sOSRequest.findMany({orderBy: { createdAt: "desc" },});return records.map((sos) => {// Ask Cedar whether this viewer is permitted to see exact coordinatesconst decision = authorize(viewer, "ViewExactLocation", {type: "SOSRequest",id: sos.id,requesterId: sos.requesterId,});if (decision.allowed) {// Full unredacted operational payload for rescue unitsreturn {id: sos.id,latitude: sos.latitude,longitude: sos.longitude,contactPhone: sos.contactPhone,description: sos.description,status: sos.status,};}// Privacy-redacted public payload for civilians (~1km fuzzed grid)return {id: sos.id,latitude: sos.fuzzyLatitude,longitude: sos.fuzzyLongitude,contactPhone: "[Redacted for civilian security]",description: sos.description,status: sos.status,};});}}
Testing Policy Correctness with Vitest
A critical benefit of AWS Cedar is that policies can be tested as pure functions with zero database mocks. We built a comprehensive test suite running under Vitest:
plaintext
import { describe, it, expect } from "vitest";import { authorize } from "@/authz/cedar";describe("Crisis Cedar Policies", () => {const responder = { id: "u-rescue", role: "RESPONDER" as const };const civilian = { id: "u-citizen", role: "RESIDENT" as const };const sos = { type: "SOSRequest" as const, id: "sos-1", requesterId: "u-citizen" };it("permits responders to see exact coordinates", () => {const decision = authorize(responder, "ViewExactLocation", sos);expect(decision.allowed).toBe(true);expect(decision.reasons).toContain("responders-see-exact-sos");});it("redacts exact coordinates for other residents", () => {const stranger = { id: "u-stranger", role: "RESIDENT" as const };const decision = authorize(stranger, "ViewExactLocation", sos);expect(decision.allowed).toBe(false);});it("strictly forbids self-corroboration", () => {const incident = {type: "Incident" as const,id: "inc-42",reporterId: "u-citizen",status: "UNVERIFIED"};const decision = authorize(civilian, "CorroborateIncident", incident);expect(decision.allowed).toBe(false);expect(decision.reasons).toEqual(["no-self-corroboration"]);});});
Every single assertion executes in less than 2 milliseconds, providing instant feedback during local development and CI builds.
Cloud Deployment Lessons Learned
When scaling serverless Next.js applications backed by cloud PostgreSQL and AWS services, we encountered three valuable lessons:
- Transaction Pooling vs. Session Pooling: Prisma running in serverless environments exhausts PostgreSQL connection limits rapidly. Connecting via PgBouncer on port
6543(?pgbouncer=true) is essential for high concurrency. However, schema migrations (prisma db push) require a direct session connection (port5432). Structuring our build scripts to dynamically toggle between the two eliminated cold-start connection crashes.
- Formally Verified Security Brings Peace of Mind: In an emergency response system, bugs are not just glitches—they are life safety liabilities. Having Cedar’s automated reason diagnostics (
diagnostics.reason) returned in authorization decisions allowed our UI to present clear, intelligible denial notices to users without leaking database internals.
- WebAssembly Brings Cloud Policies to the Edge: Running AWS Cedar compiled to WebAssembly inside the serverless container provided the security guarantees of Amazon Verified Permissions with zero latency penalties.
Conclusion & Resources
By combining AWS Cedar with modern serverless architecture, we built a crisis response platform that is resilient, blazingly fast, and respectful of civilian privacy.
If you are building applications where data sensitivity, multi-role interactions, and audit requirements meet, I strongly recommend exploring AWS Cedar for your authorization needs.
Helpful Resources:
- AWS Cedar Policy Language: https://www.cedarpolicy.com
- Amazon Verified Permissions: https://aws.amazon.com/verified-permissions/
- Neighbourlink GitHub Repository: https://github.com/asry16/Neighbourlink
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article