Skip to content

WebSocket Connection Issue - Resolution

Date: November 15, 2025 Issue: Edge client cannot connect to WebSocket Status: 🟢 RESOLVED - Secret mismatch identified


Issue Summary

The edge client is getting 403 Forbidden when attempting WebSocket connection. Root cause identified: EDGE_SECRET mismatch between client and server.


Root Cause Analysis

What the Edge Client is Using

From their test script and issue report:

EDGE_SECRET=<generated_hex>

What the Backend Has (in .env)

From /Users/justin-genies/Code/archety/.env:

EDGE_SECRET=<generated_hex>

The Problem

The secrets don't match!

  • Edge client: b3c7ddc6...
  • Backend .env: 74a0e606...

This causes the backend to reject authentication with 403 Forbidden.


Solution Options

Update the edge client to use the backend's secret:

# In edge client .env file
EDGE_SECRET=<generated_hex>

Pros: - No backend changes needed - Works immediately - Backend secret already set

Cons: - Requires edge client update

Option 2: Update Backend

Update backend .env to match edge client's secret:

# In backend .env file
EDGE_SECRET=<generated_hex>

Pros: - No edge client changes needed

Cons: - Requires backend restart - Need to update Railway environment too

Option 3: Generate New Secret (Production-Ready)

Generate a fresh secret and update both:

# Generate new secret
openssl rand -hex 32

# Example output:
# a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890

# Update both .env files with the same value

Pros: - Clean start - Production-ready secret - Both sides aligned

Cons: - Requires updates on both sides


Step 1: Tell Edge Client Engineer

Send them this message:

Hi!

Found the issue - we have a secret mismatch.

Please update your .env file:

EDGE_SECRET=<generated_hex>

This matches what's configured on the backend.

After updating:
1. Restart your edge client
2. Run: node test_websocket.js
3. You should see: ✅ WebSocket connected successfully!

Let me know if you still have issues!

Step 2: Verify Railway Configuration

Make sure Railway has the correct secret:

# Check Railway variables
railway variables --service archety-backend-dev

# If EDGE_SECRET is not set or different, update it:
railway variables set EDGE_SECRET=<generated_hex> --service archety-backend-dev

Step 3: Test Connection

After edge client updates their secret, test with:

# From backend repo
python test_websocket_connection.py

# Expected output:
# ✅ WebSocket connected successfully!
# ✅ Pong received - keepalive working!

Additional Issues Found

1. WebSocket Endpoint Exists ✅

The backend DOES have the WebSocket endpoint at /edge/ws: - File: app/api/edge_routes.py:279-381 - Path: /edge/ws - Auth: Bearer token with EDGE_SECRET - Status: ✅ Fully implemented

2. Authentication Method Correct ✅

Edge client is sending correct headers:

Authorization: Bearer {EDGE_SECRET}
X-Edge-Agent-Id: edge_13238407486

Backend expects:

auth_header = websocket.headers.get("authorization")
# Validates: Bearer {EDGE_SECRET}

Status: ✅ Correct format, just wrong secret

3. Backend Logging Is Comprehensive ✅

Backend has excellent debug logging:

logger.info(f"🔍 WebSocket connection attempt from edge_agent_id={edge_agent_id}")
logger.info(f"🔍 Auth header: {auth_header[:50]}...")
logger.info(f"🔍 Token verification result: {auth_token}")

Status: ✅ Should show clear auth failures in logs


What Changed on the Backend

Looking at the backend code (app/api/edge_routes.py:279-381), the WebSocket endpoint:

  1. Accepts connections at: wss://backend/edge/ws?edge_agent_id={id}
  2. Requires headers:
  3. Authorization: Bearer {EDGE_SECRET}
  4. X-Edge-Agent-Id: {id} (optional)
  5. Validates token using verify_edge_token() from app/edge/auth.py
  6. Supports two auth modes:
  7. Simple secret match: token == EDGE_SECRET
  8. HMAC token: Base64-encoded edge_agent_id:user_phone:timestamp:signature

The edge client is using simple secret mode, which is supported!


Testing After Fix

1. Edge Client Test

cd /path/to/edge-relay

# Make sure .env has correct secret
echo "EDGE_SECRET=<generated_hex>" > .env

# Run test
node test_websocket.js

Expected output:

✅ WebSocket connected successfully!
📥 Received message: {"type":"pong"}
Test complete - closing connection
🔌 WebSocket closed:
   Code: 1000

2. Backend Logs to Verify

Check Railway logs for:

Success indicators:

✅ Token verified for edge_agent_id=edge_13238407486
✅ WebSocket connection established for edge_13238407486
✅ Edge agent edge_13238407486 registered with WebSocket manager
🏓 Sent pong to edge_13238407486

Failure indicators (current state):

❌ Token verification failed for edge_agent_id=edge_13238407486
❌ WebSocket connection rejected: invalid token


Summary for Edge Client Engineer

The Fix (1 minute)

Update your .env file:

EDGE_SECRET=<generated_hex>

Why It Failed

Your secret: <redacted> Backend secret: <redacted>

These didn't match, so the backend rejected authentication.

Everything Else Was Correct

  • ✅ WebSocket endpoint exists at /edge/ws
  • ✅ URL format is correct
  • ✅ Headers are correct format
  • ✅ Query parameters are correct
  • ✅ Your test script is perfect
  • ✅ Fallback to HTTP polling is working

Only issue: Wrong secret value

After Update

  1. Your WebSocket will connect immediately
  2. You'll get pong responses to ping messages
  3. Backend can push commands in real-time
  4. HTTP polling will stop (WebSocket takes over)

For Production Deployment

Before going to production, let's use a more secure secret:

# Generate production secret
SECRET=$(openssl rand -hex 32)

# Backend: Set on Railway production environment
railway variables set EDGE_SECRET=$SECRET --environment production

# Edge Client: Add to production .env
echo "EDGE_SECRET=$SECRET" >> .env.production

Never commit secrets to git!


Contact

Issue Found By: Backend Engineer 2 Resolution: Secret mismatch Fix Time: 1 minute Status: Ready to deploy


Document Version: 1.0 Created: November 15, 2025 Status: Resolution identified - waiting for edge client update