Security¶
Core Security Philosophy¶
JunctionRelay is built from the ground up with Zero Trust principles applied at every architectural boundary. The system enforces strict separation between components, no implicit trust across network layers, and zero reliance on any unsecured cloud-to-local interactions.
Every interaction between components is authenticated, authorized, and scoped to the minimum necessary privileges.
Threat Model Summary¶
Threat Category | Protection Strategy |
---|---|
Cloud credential leakage | Zero trust proxy model, no credentials on local devices |
Cross-site attacks (CSRF/XSS) | Browser memory tokens only, no persistent storage |
Token theft | Short-lived JWT tokens, refresh flows strictly backend controlled |
Device impersonation | Hardware MAC-based registration, strict device identity management |
Cloud compromise | No cloud-to-local inbound connectivity |
Local compromise | Optional full offline local mode, local admin-only user creation |
Firmware supply chain | OTA firmware releases validated server-side via GitHub releases |
Man-in-the-middle (MITM) | Enforced HTTPS/TLS on all cloud API endpoints |
Database compromise | Encrypted refresh tokens, direct PostgreSQL operations for consistency |
Token replay attacks | MAC-locked device identity, refresh token rotation capabilities |
Zero Trust Enforcement¶
🔐 No Cloud Credentials Stored Locally¶
- All Clerk OAuth, Stripe API keys, and PostgreSQL secrets remain exclusively in cloud backend environment.
- Local backend instances do not store or handle any cloud credentials.
🔐 Backend-Only Token Exchanges¶
- OAuth code exchanges happen entirely server-side within the cloud backend.
- Frontend receives only opaque short-lived backend JWT tokens scoped to user identity.
🔐 Fully API-Driven¶
- Frontend performs no privileged actions; all logic flows through secured backend API endpoints.
- Devices interact exclusively via device-specific cloud APIs or secured WebSocket local interfaces.
🔐 No Reverse Cloud Connections¶
- The cloud backend never directly initiates communication with local backends.
- Local backends poll cloud proxy APIs when needed for pending cloud tasks.
🔐 Device Identity¶
- ESP32 devices uniquely identified via MAC address.
- Registration requires single-use short-lived registration tokens issued by cloud backend.
- Devices persist issued JWTs and refresh tokens locally (ESP32 Preferences NVS).
Token Lifecycle Management¶
Backend User Tokens¶
- Short-lived JWT tokens (~8 hour lifetime)
- Refresh tokens issued for long-term browser session continuity
- All refresh token handling server-side only
- Direct PostgreSQL storage for immediate consistency and atomic operations
Device Tokens¶
- Device JWT tokens (~8 hour lifetime)
- Device refresh tokens issued after successful registration
- Refresh process fully automated within ESP32 firmware SDK
- Device tokens contain both
deviceId
anduserId
claims for proper authorization
Session Storage Model¶
- Frontend tokens stored strictly in browser memory (no LocalStorage, IndexedDB, or persistent cookies)
- Logout fully clears all frontend state
- PostgreSQL-based session store with immediate consistency guarantees
Refresh Token Architecture¶
PostgreSQL-Based Token Storage¶
- Direct database operations - No Redis dependency for critical token operations
- Atomic transactions - Token validation, creation, and removal operations are ACID-compliant
- Type isolation - User and device tokens stored with explicit
TokenType
field ("user"
or"device"
) - Immediate consistency - Token operations complete synchronously with API responses
Token Storage Schema¶
CREATE TABLE "RefreshTokens" (
"KeyId" VARCHAR NOT NULL, -- userId or deviceId
"Token" VARCHAR NOT NULL, -- the refresh token (unique)
"TokenType" VARCHAR NOT NULL, -- 'user' or 'device'
"CreatedAt" TIMESTAMP NOT NULL
);
Cold Boot Recovery¶
- Session restoration - cloud backend automatically validates stored refresh tokens on API requests
- Transparent refresh - expired access tokens automatically refreshed using stored refresh tokens
- Failure handling - invalid refresh tokens trigger automatic session cleanup
- Zero manual intervention - cloud connectivity restored without user re-authentication
Token Lifecycle Coordination¶
- Frontend logout - triggers refresh token removal from PostgreSQL
- Cloud logout - invalidates refresh tokens and clears session state
- Device deregistration - removes all associated device refresh tokens
- User session cleanup - removes all user refresh tokens on demand
Security Benefits¶
- Persistent cloud connectivity - Device authentication survives service restarts
- Proper logout semantics - Both cloud and session state cleared on logout
- OAuth2 compliance - Follows standard patterns for refresh token management
- Database encryption at rest - PostgreSQL-level encryption protects stored tokens
- Automatic expiration - Dead sessions cleaned up when refresh attempts fail
Device Registration Security Model¶
Direct Database Device Operations¶
- Immediate device creation -
CreateDeviceAsync()
writes directly to PostgreSQL - Atomic registration - Device creation and token issuance in single transaction
- No queue delays - Registration completes synchronously with API response
- Consistent state - Device always exists in database before tokens are issued
Short-Lived Registration Tokens¶
- Registration tokens expire after 15 minutes
- Stored in memory cache (
Dictionary<string, CloudRegistrationToken>
) for performance - Devices must present valid registration token during initial onboarding
- After registration, devices receive device-specific refresh and JWT tokens stored in PostgreSQL
MAC-Based Identity Lock¶
- Device MAC address permanently tied to initial registration record in PostgreSQL
Devices
table - Prevents spoofing or duplicate registrations
UniqueIdentifier
field enforces unique constraint on device MAC addresses
Device Status Management¶
- Direct status updates - Device activation/deactivation writes directly to PostgreSQL
- License enforcement - Pro license limits enforced at device activation time
- Atomic operations - Multiple device status changes handled in database transactions
Cloud Backend Data Architecture¶
PostgreSQL-First Design¶
- All critical operations use direct PostgreSQL writes for immediate consistency
- Device management - Create, update, delete, activate operations are synchronous
- User management - Authentication state and session management in PostgreSQL
- Notification settings - Device notification preferences stored and updated directly
Redis Usage (Limited Scope)¶
- Health reporting only - High-volume device health data queued via Redis for background processing
- Non-critical data - Health reports don't require immediate consistency
- Background worker -
JunctionRelay_Worker
processes health data asynchronously - Stateless processing - Health data processor is horizontally scalable
Data Consistency Benefits¶
- Immediate feedback - API operations complete when database writes succeed
- Atomic device operations - License enforcement and device updates are transactional
- Session reliability - Token validation always reflects current database state
- Simplified error handling - Direct database operations provide immediate success/failure feedback
Secrets Management¶
Local Backend (junctionrelay_server_local)¶
LOCAL_ENCRYPTION_KEY
(optional for secret DB encryption)DATABASE_PASSWORD
(if SQLite password enabled)- No Clerk, Stripe, PostgreSQL, or cloud credentials needed
Cloud Backend (junctionrelay_cloud)¶
CLERK_SECRET_KEY
- Backend API authenticationCLERK_OAUTHCLIENTID
andCLERK_OAUTHCLIENTSECRET
- OAuth flow credentialsSTRIPE_SECRET_KEY
- Subscription managementSTRIPE_WEBHOOK_SECRET
- Webhook verificationPOSTGRES_CONNECTION_STRING
- Primary database connectionREDIS_CONNECTION_URL
- Background task queue (health reporting only)- All environment variables injected securely at deployment
API Security Architecture¶
Authentication Endpoints¶
/api/auth/initiate-login
- Generates Clerk OAuth URLs (public)/api/auth/exchange-code
- Exchanges OAuth codes for tokens (public)/api/auth/refresh
- Refreshes user tokens using PostgreSQL-stored refresh tokens/api/auth/logout
- Removes refresh tokens from PostgreSQL/api/auth/validate-token
- Validates current user session
Device Management Endpoints¶
/cloud/devices/generate-registration-token
- Creates device registration tokens (user auth required)/cloud/devices/register
- Registers devices with MAC validation (public, token-protected)/cloud/devices/refresh
- Refreshes device tokens using PostgreSQL validation (device auth)- All CRUD operations require proper user or device authentication
Authorization Model¶
- User JWTs contain
userId
,email
, andhasLicense
claims - Device JWTs contain
deviceId
anduserId
claims for dual authorization - Refresh tokens validated against PostgreSQL before issuing new JWTs
- License enforcement checked at device activation time
OTA Firmware Security¶
- Firmware releases sourced exclusively from trusted GitHub repositories
- OTA downloads occur via secure cloud proxy APIs
- Cloud backend validates firmware before presenting flash options to frontend UI
- All OTA triggers require explicit user initiation from frontend dashboard
Browser Security Posture¶
- Frontend builds contain zero embedded secrets
- Browser state stored exclusively in ephemeral memory
- Supports full air-gapped local deployment with no external connectivity
- No permanent credential leakage risk on client devices
- Fully safe for usage in shared browser environments
Database Security¶
PostgreSQL Security Features¶
- Connection encryption - All connections use TLS
- Parameterized queries - All SQL operations use parameter binding to prevent injection
- Role-based access - Database users have minimal required permissions
- Audit logging - Database operations logged for security monitoring
Data Protection¶
- Encrypted at rest - PostgreSQL-level encryption for stored tokens
- Network encryption - TLS for all database connections
- Secret rotation - Database credentials rotatable without service interruption
- Backup security - Database backups encrypted and access-controlled
Operational Security¶
Service Isolation¶
- Cloud backend - Stateless, horizontally scalable, no local network access
- Background worker - Isolated Redis consumer, no direct API access
- Local backend - Fully isolated, optional cloud connectivity
- Frontend - Static build, no backend secrets
Monitoring and Alerting¶
- Authentication failures logged and monitored
- Token validation errors tracked for abuse detection
- Database connection failures trigger operational alerts
- Device registration anomalies flagged for review
Future Security Enhancements¶
- Refresh token rotation - Automatic rotation on each use for enhanced security
- Enhanced audit logging across both frontend and backend components
- Token usage tracking - Monitor refresh token usage patterns
- Automated cleanup - Background cleanup of expired refresh tokens
- Rate limiting - API endpoint rate limiting for abuse prevention
- Device attestation - Enhanced firmware validation and device identity verification
- Multi-factor authentication - Additional authentication factors for sensitive operations
Summary¶
JunctionRelay enforces an aggressive zero-trust security model that fully separates trust boundaries between local devices, local operators, cloud services, and public networks. The PostgreSQL-first architecture ensures immediate consistency for all critical operations while maintaining strict security posture. The system supports fully offline deployments for maximum control, while allowing trusted hybrid cloud integrations where licensed. Redis usage is limited to non-critical background processing, ensuring that all authentication and device management operations maintain ACID compliance and immediate consistency guarantees.