Event-Driven Integration - Testing Guide

Testing user synchronization via NATS events published by Better Auth. Important: Better Auth publishes events to NATS (message queue), not webhooks. This guide covers testing NATS event consumption via the user_sync_handler.go.

Prerequisites

1. NATS Server Running

Better Auth publishes events to a NATS server. Ensure NATS is running:
# Check docker-compose has NATS service
docker-compose up nats

# Or verify NATS is accessible
nats ping -s nats://localhost:4222

2. Backend Connected to NATS

Verify your .env has correct NATS connection:
# backend/.env
NATS_URL=nats://localhost:4222

3. Install NATS CLI Tools

# Using brew (macOS)
brew install nats-io/nats-tools/nats

# Using apt (Linux)
apt-get install nats-tools

# Or download from https://github.com/nats-io/natscli/releases

Testing Options

Triggers a real user.created event from Better Auth to NATS

Step 1: Start Backend

cd backend/go
air  # or go run cmd/server/main.go
Backend should be running on http://localhost:8080 and connected to NATS.

Step 2: Monitor NATS Events

In a new terminal, subscribe to NATS user events:
nats sub "user.>"
You’ll see output like:
Listening on [user.>]
Keep this terminal open to see events as they arrive.

Step 3: Trigger User Creation

Go to your frontend and sign up:
  1. Navigate to http://localhost:4321 (Astro) or http://localhost:3000 (SolidStart)
  2. Click “Sign Up”
  3. Register with email/password or OAuth (Google, GitHub)
  4. Check NATS subscriber terminal for incoming event

Step 4: Verify Event Received

You should see a message like:
[1] Received on "user.sync":
{"event":"user.created","timestamp":"2024-04-16T10:30:00Z","data":{"userId":"...","email":"user@example.com","name":"User Name","emailVerified":true,"roles":["user"],...}}

Step 5: Verify Backend Processed Event

Check backend logs:
# Look for log message
# "User synced successfully" or similar from user_sync_handler.go
And verify user created in PostgreSQL:
psql -U postgres -d go_core_uat -c "SELECT id, email, name FROM users LIMIT 5;"

Option 2: Publish Manual Test Event to NATS

Simulates a Better Auth event without needing user signup

Step 1: Start Backend

cd backend/go
air

Step 2: Subscribe to Events

In terminal 1:
nats sub "user.>"

Step 3: Publish Test Event

In terminal 2, publish a test user.created event:
nats pub user.sync '{
  "event":"user.created",
  "timestamp":"2024-04-16T10:30:00Z",
  "data":{
    "userId":"test_user_123",
    "email":"testuser@example.com",
    "name":"Test User",
    "emailVerified":true,
    "isAnonymous":false,
    "isActive":true,
    "roles":["user"],
    "organizationId":"org_default"
  }
}'

Step 4: Verify Reception

Check terminal 1 (subscriber) - you should see the event published. Check backend logs - verify user_sync_handler.go processed it. Check PostgreSQL:
psql -U postgres -d go_core_uat -c "SELECT email, name FROM users WHERE email='testuser@example.com';"

Option 3: Monitor Live Event Stream

Watch all Better Auth events in real-time
# Subscribe to all user events
nats sub "user.>"

# Or watch all subjects
nats sub ">"
Then trigger events by:
  • Signing up new users in frontend
  • Logging in (may trigger user.updated)
  • Updating user profile

Better Auth Event Format

Events published by Better Auth follow this structure:
{
  "event": "user.created|user.updated|user.deleted",
  "timestamp": "2024-04-16T10:30:00Z",
  "data": {
    "userId": "auth_id_varchar26",
    "email": "user@example.com",
    "phone": "+1234567890",
    "name": "User Name",
    "emailVerified": true,
    "isAnonymous": false,
    "isActive": true,
    "roles": ["user", "admin"],
    "organizationId": "org_id_or_default"
  }
}
Processing: Your backend’s user_sync_handler.go consumes these events and syncs user data to PostgreSQL users table.

Verification Checklist

After testing, verify:
  • NATS CLI nats sub "user.>" receives events
  • Backend logs show user_sync_handler processing events (no errors)
  • User created/updated in PostgreSQL users table with correct auth_id
  • User email, name, roles match Better Auth data
  • User organization_id set correctly (from event data or default)
  • Backend stays connected to NATS (no “connection lost” errors)

Troubleshooting

NATS server not running

Error: Error: Could not connect to NATS server Fix:
# Start NATS via docker-compose
docker-compose up nats

# Or verify NATS is accessible
nats ping -s nats://localhost:4222

Backend not connected to NATS

Error: Backend logs show “Failed to connect to NATS” or no events being processed Fix:
  1. Check .env has correct NATS_URL:
    echo $NATS_URL
    # Should output: nats://localhost:4222
    
  2. Verify NATS server is running:
    docker ps | grep nats
    
  3. Restart backend after .env changes:
    # Kill air process and restart
    air
    

Event not received in subscriber

Error: nats sub "user.>" is running but no events appear Checks:
  1. Is backend connected to NATS? (check backend logs)
  2. Is an event being triggered? (sign up user or publish manually)
  3. Is NATS working? Test with manual publish:
    nats pub test.message "hello"
    nats sub test.message
    # In another terminal, should see "hello"
    

User not synced to PostgreSQL

Error: Event received but users table unchanged Cause: user_sync_handler.go failed to process event Fix:
  1. Check backend logs for error message
  2. Verify PostgreSQL connection:
    psql -U postgres -d go_core_uat -c "\dt users;"
    
  3. Check foreign key constraints:
    psql -U postgres -d go_core_uat -c "\d users"
    

Email already exists error

Expected behavior: If user already exists, user_sync_handler should update, not error. If it errors:
  • Check FindByEmail logic in handler
  • Verify PostgreSQL users table structure
  • Check backend logs for specific error

Duplicate events received

Expected: Events may be published multiple times (at-least-once delivery). Handler should be idempotent. Verify: Running handler twice with same userId should not create duplicates.

Event Types & Handling

user.created

  • Triggered: New user signs up (email/password or OAuth)
  • Action: Create new record in PostgreSQL users table
  • Handler: user_sync_handler.go CreateUser logic

user.updated

  • Triggered: User updates profile (name, email, roles)
  • Action: Update existing record in PostgreSQL users table
  • Handler: user_sync_handler.go UpdateUser logic

user.deleted

  • Triggered: User account deleted (if implemented)
  • Action: Mark user as inactive or delete record
  • Handler: Currently handled by DeleteUser logic (if present)

Future: Multi-Tenant Support

When ready to support multiple organizations:
  1. Handle organizationId in events:
    • Currently set to "org_default"
    • Will be dynamic when users can create/join orgs
  2. Update event handler (user_sync_handler.go):
    // Use organizationId from event, not hardcoded default
    orgID := event.Data.OrganizationID
    
  3. Add organization management events:
    • organization.created - New org created
    • organization.updated - Org info changed
    • organizationMembership.created - User joins org
    • organizationMembership.deleted - User leaves org

Next Steps

  1. ✅ Verify NATS server is running
  2. ✅ Start backend and check NATS connection
  3. ✅ Test with end-to-end user signup
  4. ✅ Monitor events in NATS subscriber
  5. 📝 Verify users synced to PostgreSQL
  6. 📝 Review user_sync_handler.go error handling
  7. 📝 Set up monitoring alerts for NATS connection failures

Support

If you encounter issues:
  • Review backend logs for NATS handler errors
  • Verify NATS server is running and accessible
  • Check .env has correct NATS_URL
  • Verify PostgreSQL users table exists and has correct schema
  • Run nats ping to test NATS connectivity
  • Check user_sync_handler.go implementation for custom logic