A learning journey into WebSockets, JWT authentication, and peer-to-peer architecture
3-4 minute read | View on GitHub
The Challenge
Modern chat applications rely heavily on centralized servers that handle everything—messages, files, user management. But what if you wanted to build something different? What if files could transfer directly between users while still having the convenience of a central coordination point?
That's exactly what I set out to explore while learning FastAPI.
The Vision: Hybrid Architecture
Instead of building yet another fully centralized chat app, I designed a hybrid system that combines the best of both worlds:
- Centralized coordination for user discovery and message routing
- Decentralized file transfers for speed and efficiency
Think of it like a LAN party where one computer acts as the "lobby" (the server), but when you want to share a game save or file, you transfer it directly to your friend's machine.
Why This Approach?
The Problem with Pure Centralization
When you upload a 500MB file to a chat app, it typically goes:
Your computer → Server → Friend's computer
This means:
- The server needs massive storage
- Upload happens twice (you upload, friend downloads)
- Server becomes a bottleneck
- Privacy concerns (server has all your files)
The P2P Solution
My system works differently:
Your computer → Friend's computer (direct)
Server only shares: "Hey, Alice has a file available at 192.168.1.100:8001"
Benefits:
- LAN-speed transfers (100+ MB/s instead of internet speeds)
- No server storage needed (server only handles metadata)
- Privacy-friendly (files never touch the central server)
- Scalable (server handles lightweight messages, not heavy files)
Technical Implementation
The Server Stack
Built with FastAPI and WebSockets, the server handles:
- JWT Authentication: Secure, stateless auth with access and refresh tokens
- User Registry: Tracks who's online via WebSocket connections
- Message Routing: Broadcasts or private message delivery
- Metadata Exchange: Shares file locations between peers
# The server never sees actual files
await conn.send_json({
"type": "file",
"from_user": "alice",
"file_name": "document.pdf",
"p2p_ip": "192.168.1.100:8001" # Direct to peer
})
The Client Design
Each client is actually two servers in one:
- WebSocket Client: Connects to central server
- Local HTTP Server: Serves shared files to other peers
When you share a file:
- Your client adds the path to an allowlist
- Sends metadata to the central server
- Server routes metadata to recipient(s)
- Recipients connect directly to YOUR HTTP server
- File transfers peer-to-peer
Security Considerations
Path Validation: Clients only serve explicitly shared files
ALLOWED_PATHS = set() # Whitelist approach
ALLOWED_PATHS.add("/home/user/shared/document.pdf")
JWT Tokens: All WebSocket connections require valid authentication
LAN-Only: P2P servers bind to local IP, not exposed publicly
The Learning Journey
What I Built Myself
- The entire architecture and design
- Server-side logic (JWT, WebSocket routing, message handling)
- P2P file serving endpoints
- The basic client boilerplate
Where I Got Help
I used Gemini AI to implement the GUI layer (client-gemini.py) using PySide6. Why? Because I wanted to focus my learning on backend architecture, not wrestling with Qt layouts.
Important note: The GUI client is untested. AI-generated code has bugs—that's expected and normal. If you're interested in contributing, testing and fixing the GUI would be hugely valuable!
Key Features
✅ Real-time messaging with broadcast and private chat
✅ Direct P2P file transfers at LAN speeds
✅ Folder browsing via HTTP interface
✅ Auto-generated usernames based on system specs
✅ Live user directory showing online/offline status
✅ Configurable polling for server health checks
Code Highlights
Automatic Username Generation
def generate_auto_username():
arch = platform.machine() # x86_64, arm64, etc.
py_ver = f"P{sys.version_info.major}{sys.version_info.minor}"
unique_id = str(uuid.uuid4())[:4]
return f"{arch}_{py_ver}_{unique_id}"
# Example: "x86_64_P311_a4f2"
Secure File Serving
@app.get("/download/file")
async def download_file(path: str):
real = os.path.abspath(path)
# Security: Only serve explicitly shared files
if not any(real.startswith(p) for p in ALLOWED_PATHS):
raise HTTPException(403, "Access Denied")
if not os.path.isfile(real):
raise HTTPException(404, "File not found")
return FileResponse(real, filename=os.path.basename(real))
Lessons Learned
1. Architecture Matters More Than Code
The hybrid approach was the key insight. Once I had the architecture clear, implementation was straightforward.
2. WebSockets Are Powerful
FastAPI's WebSocket support made real-time communication surprisingly simple. The hardest part was managing connection lifecycles.
3. Security Is About Layers
- JWT for authentication
- Path validation for file access
- LAN-only networking
- Explicit sharing via allowlists
No single layer is perfect, but together they create a reasonably secure system for trusted networks.
4. AI Is a Tool, Not a Solution
Using Gemini for the GUI was helpful, but the code needs human review and testing. AI accelerates development but doesn't replace understanding.
What's Next?
Current limitations and potential improvements:
Missing features:
- Encryption for P2P transfers (currently plaintext HTTP)
- File transfer resume/retry
- Bandwidth throttling
- Multi-threaded file serving
Future possibilities:
- STUN/TURN for NAT traversal (enable internet-wide P2P)
- Compression for large transfers
- File integrity verification with checksums
- End-to-end encrypted messaging
Try It Yourself
The project is open source and available on GitHub. Whether you want to:
- Learn FastAPI and WebSockets
- Understand hybrid architectures
- Contribute to an educational project
- Test (and fix!) the GUI client
You're welcome to dive in. The codebase is designed to be readable and educational.
Repository: github.com/hejhdiss/lan-collaboration
Quick Start
# Start the server
python main2.py -p 8000 -k "your_secret_key"
# Run the GUI client (untested!)
python client-gemini.py
# Or build your own using the boilerplate
python client-basic.py
Final Thoughts
This project taught me that good architecture can make complex systems feel simple. By separating concerns—centralized coordination vs. decentralized transfers—I built something that's both efficient and maintainable.
The hybrid approach isn't just theoretical; it's practical for LAN environments where you want the convenience of a central server without its limitations.
Most importantly, I learned by building something real, making mistakes, and iterating. That's what makes side projects valuable.
The architecture is mine. The learning is mine. The bugs in the GUI? Well, those might be Gemini's. 😄
Want to contribute? Check out the Contributing Guide. Found a bug? Open an issue. Have questions? Start a discussion.
Built as a FastAPI learning project | Apache License 2.0 | Copyright 2026 @hejhdiss
Top comments (0)