A secure, real-time messaging app built with Rust and WebSockets, featuring JWT authentication, bcrypt password hashing, and a custom retro terminal UI.
Minimalist entry point with focus-centered design.

Real-time communication with distinct visual feedback for user messages.

- Real-Time Communication: Instant messaging powered by WebSockets.
- Secure Authentication: JWT-based auth with bcrypt password hashing. Tokens are verified server-side on every WebSocket connection.
- XSS Protection: All HTML rendered from Markdown is sanitized via
DOMPurifybefore touching the DOM. - Rate Limiting: Brute-force protection on
/loginand/registerviatower_governor— 5 attempts allowed, then 1 per 30 seconds per IP. - Persistent History: SQLite integration via
SQLx(async). Last 100 messages are loaded automatically on connect. - Rich Content Rendering:
- Markdown: Full GFM support via
Marked.js. - Syntax Highlighting: Multi-language code blocks via
Highlight.js. - Math: LaTeX equation rendering via
KaTeX.
- Markdown: Full GFM support via
- User Color Identity: Deterministic per-user colors assigned server-side from the username hash — consistent across sessions and clients.
- Structured Logging:
tracing+tracing-subscriberwithRUST_LOGenv filter support. - Retro UI/UX: CRT scanlines, monochromatic palette, and pixel-perfect terminal design.
| Component | Technology |
|---|---|
| Language | Rust 🦀 |
| Framework | Axum 0.8 |
| Async Runtime | Tokio |
| Database | SQLite + SQLx (async) |
| Auth | JWT (jsonwebtoken) + bcrypt |
| Rate Limiting | tower_governor |
| Serialization | Serde + Serde JSON |
| Logging | tracing + tracing-subscriber |
| Component | Technology |
|---|---|
| Logic | Vanilla JavaScript + WebSocket API |
| Sanitization | DOMPurify |
| Markdown/Math | Marked.js, Highlight.js, KaTeX |
| Styling | Pure CSS3 (variables, flexbox, custom scrollbars) |
src/
├── main.rs # Entry point: server config, DB init, routing, middleware.
├── state.rs # Shared AppState (broadcast channel, DB pool, JWT secret).
└── handlers.rs # Business logic: auth endpoints, WebSocket loop, static files.
-
JWT Authentication Flow: On login, the server issues a signed JWT. The client attaches it as a query parameter when opening the WebSocket. The server validates the signature before upgrading the connection — unauthenticated requests are rejected with
401. -
Server-Side Identity: The server ignores any
nameorcolorfields sent by the client. Both are derived server-side from the verified JWT claims, preventing impersonation and XSS via crafted field values. -
Broadcast Architecture:
tokio::sync::broadcasthandles one-to-many message distribution. Lagged receivers are detected and logged rather than silently dropped. -
Client-Side Rendering: The server sends raw text; all Markdown, LaTeX, and syntax highlighting is processed in the browser. DOMPurify sanitizes the resulting HTML before injection.
- Rust (edition 2021+)
git clone https://github.com/mateocampagna/rust-retro-chat
cd rust-retro-chat
# Create your environment file
cp .env.example .env
# Edit .env and set a strong JWT_SECRET
cargo runThe server starts at http://localhost:3000.
| Variable | Description |
|---|---|
JWT_SECRET |
Secret key used to sign and verify JWT tokens. Use a long random string. |
RUST_LOG=info cargo run # default — server events only
RUST_LOG=warn cargo run # warnings and errors only
RUST_LOG=debug cargo run # full verbose output- Basic WebSocket implementation
- Custom retro styling
- Message history persistence (SQLite)
- Markdown, code & LaTeX support
- Modular codebase
- User authentication (bcrypt + JWT)
- Server-side user color identity
- XSS protection (DOMPurify)
- Rate limiting on auth endpoints
- Structured logging (tracing)
- Logout button
- Online users list
⚠️ Disclaimer: This project was developed for learning purposes. Its goal is to explore the Rust ecosystem, WebSockets, and real-time application architecture.
Created by Mateo Campagna