Real-time, room-based chat — built with Go, WebSockets, and PostgreSQL.
Live demo: wireroom.up.railway.app
WireRoom is a full-stack real-time chat application built from scratch. Users authenticate via Google, GitHub, or a username/password, then create or join private rooms using shareable 8-character codes. Every interaction — messages, typing indicators, reactions, participant updates — is delivered instantly over persistent WebSocket connections.
The backend is written in Go and handles concurrent rooms using goroutines and mutexes. There are no third-party real-time services — the WebSocket server is hand-rolled.
Authentication
- Google and GitHub OAuth 2.0 with state parameter CSRF protection
- Username/password fallback with bcrypt hashing
- JWT-based sessions stored in HTTP-only cookies with 30-day expiry
- Auto-login on page refresh via persisted session token
Rooms
- Create private rooms with randomly generated 8-character codes
- Optional room password set at creation — joiners are prompted if required
- Join any room by code — shareable via one-click copy
- Per-room username uniqueness enforced at the server
- Host role with crown indicator — automatically transferred if host leaves
Chat
- Message history: last 24 hours loaded on join, separated from live messages
- Real-time typing indicators with multi-user support ("alice and bob are typing...")
- Emoji reactions on messages — toggle on/off, live count shown as pills
- 500 character message limit enforced server-side
Host Controls
- Kick participants — kicked users are redirected immediately with a notification
- Transfer host role to any participant via right-click context menu
┌─────────────┐ HTTPS/WSS ┌──────────────────────┐
│ Browser │ ◄────────────────► │ Go HTTP Server │
│ HTML/CSS/JS│ │ (net/http) │
└─────────────┘ │ │
│ ┌────────────────┐ │
│ │ WS Handler │ │
│ │ goroutine │ │
│ │ per client │ │
│ └───────┬────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Room Registry │ │
│ │ sync.Mutex │ │
│ └───────┬────────┘ │
└──────────┼───────────┘
│
┌──────────▼───────────┐
│ PostgreSQL │
│ (Supabase) │
│ │
│ users │
│ messages │
└───────────────────────┘
Concurrency model: Each WebSocket connection runs in its own goroutine. Shared room state (client map, host pointer, member list) is protected by a sync.Mutex. Broadcasts iterate the client map under the lock and write to each connection.
Message flow:
- Client sends
{type: "message", content: "..."}over WS - Server saves to PostgreSQL, gets back the row ID
- Server broadcasts
{type: "message", id: X, user: "...", content: "..."}to all room members including sender - Frontend renders on receipt — no optimistic UI, single source of truth
| Layer | Technology |
|---|---|
| Backend | Go 1.25, gorilla/websocket |
| Auth | OAuth 2.0 (golang.org/x/oauth2), bcrypt, JWT (golang-jwt/jwt) |
| Database | PostgreSQL via Supabase (lib/pq) |
| Frontend | Vanilla HTML, CSS, JavaScript — no framework |
| Deployment | Railway (backend), Supabase (database) |
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE,
password TEXT, -- bcrypt hash, nullable for OAuth users
google_id TEXT UNIQUE,
github_id TEXT UNIQUE,
avatar_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE messages (
id BIGSERIAL PRIMARY KEY,
room_code TEXT NOT NULL,
username TEXT NOT NULL,
"content" TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_messages_room_created ON messages(room_code, created_at);Prerequisites: Go 1.20+, a PostgreSQL database (Supabase free tier works)
git clone https://github.com/Amag1n3/WireRoom
cd WireRoom
go mod downloadCreate a .env or set environment variables:
DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres?sslmode=require
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
JWT_SECRET=your-long-random-secretRun the schema from schema.sql against your database, then:
go run main.goOpen http://localhost:8080.
For local OAuth, set redirect URIs to
http://localhost:8080/auth/google/callbackandhttp://localhost:8080/auth/github/callbackin your OAuth app settings.
WireRoom/
├── main.go # Server, WebSocket handler, auth, DB, OAuth
├── go.mod
├── go.sum
└── public/
├── index.html # App shell and screen templates
├── style.css # Design system and component styles
└── app.js # WebSocket client, state management, UI logic
- Passwords are hashed with bcrypt (cost factor 10) — plaintext never stored or logged
- OAuth state parameter validated via cookie to prevent CSRF
- JWT tokens are signed with HS256 and expire after 30 days
- SSL enforced on all database connections
- Login lockout after 5 failed attempts with a 2-minute cooldown
- Message delete (own messages; host can delete any)
- Reply to specific messages
- Mobile responsive layout
- Rate limiting on message sends
- Persistent emoji reactions (currently in-memory per session)
- Room passwords
Built by Amogh — open to internship and junior engineering opportunities.