# Authentication System Setup This document describes the multi-channel authentication system for the Dexorder AI Gateway. ## Overview The gateway now implements a comprehensive authentication system using **Better Auth** with support for: - ✅ Email/Password authentication - ✅ Passkey/WebAuthn (passwordless biometric auth) - ✅ JWT token-based sessions - ✅ Multi-channel support (WebSocket, Telegram, REST API) - ✅ PostgreSQL-based user management - ✅ Secure password hashing with Argon2 ## Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ Client Apps │ │ (Web, Mobile, CLI, Telegram, etc.) │ └────────────┬────────────────────────────────┬───────────────┘ │ │ │ HTTP/REST │ WebSocket │ │ ┌────────────▼────────────────────────────────▼───────────────┐ │ Gateway (Fastify) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ Auth Routes │ │ WebSocket │ │ Telegram │ │ │ │ /auth/* │ │ Handler │ │ Handler │ │ │ └──────┬───────┘ └──────┬───────┘ └────────┬────────┘ │ │ │ │ │ │ │ └─────────────────┴────────────────────┘ │ │ │ │ │ ┌────────▼──────────┐ │ │ │ Auth Service │ │ │ │ (Better Auth) │ │ │ └────────┬──────────┘ │ │ │ │ └───────────────────────────┼────────────────────────────────┘ │ ┌────────▼────────┐ │ PostgreSQL │ │ - users │ │ - sessions │ │ - passkeys │ │ - credentials │ └─────────────────┘ ``` ## Database Schema The authentication system uses the following PostgreSQL tables: ### Core Tables 1. **users** - Core user accounts - `id` (PRIMARY KEY) - `email` (UNIQUE) - `email_verified` - `name` - `created_at`, `updated_at` 2. **user_credentials** - Password hashes - `user_id` (FOREIGN KEY → users.id) - `password_hash` (Argon2) 3. **sessions** - JWT sessions - `id` (PRIMARY KEY) - `user_id` (FOREIGN KEY → users.id) - `expires_at` - `ip_address`, `user_agent` 4. **passkeys** - WebAuthn credentials - `id` (PRIMARY KEY) - `user_id` (FOREIGN KEY → users.id) - `credential_id` (UNIQUE) - `credential_public_key` - `counter`, `transports` 5. **verification_tokens** - Email verification, password reset - `identifier`, `token`, `expires_at` ### Integration Tables 6. **user_licenses** - User authorization & feature flags - `user_id` (FOREIGN KEY → users.id) - `license_type` (free, pro, enterprise) - `features` (JSONB) - `resource_limits` (JSONB) 7. **user_channel_links** - Multi-channel support - `user_id` (FOREIGN KEY → users.id) - `channel_type` (telegram, slack, discord, websocket) - `channel_user_id` ## Installation 1. **Install dependencies:** ```bash cd gateway npm install ``` The following packages are added: - `better-auth` - Main authentication framework - `@simplewebauthn/server` - WebAuthn/passkey support - `@simplewebauthn/browser` - Client-side passkey helpers - `@fastify/jwt` - JWT utilities - `argon2` - Secure password hashing 2. **Apply database schema:** ```bash psql $DATABASE_URL -f schema.sql ``` 3. **Configure secrets:** Copy `secrets.example.yaml` to your actual secrets file and update: ```yaml auth: secret: "YOUR-SUPER-SECRET-KEY-HERE" # Generate with: openssl rand -base64 32 ``` 4. **Configure server:** Update `config.yaml`: ```yaml server: base_url: http://localhost:3000 # Or your production URL trusted_origins: - http://localhost:3000 - http://localhost:5173 # Your web app - https://yourdomain.com ``` ## API Endpoints ### Authentication Routes All Better Auth automatic routes are available at `/api/auth/*`: - `POST /api/auth/sign-up/email` - Register with email/password - `POST /api/auth/sign-in/email` - Sign in with email/password - `POST /api/auth/sign-out` - Sign out - `GET /api/auth/session` - Get current session - `POST /api/auth/passkey/register` - Register passkey - `POST /api/auth/passkey/authenticate` - Authenticate with passkey ### Custom Routes (Simplified) - `POST /auth/register` - Register and auto sign-in - `POST /auth/login` - Sign in - `POST /auth/logout` - Sign out - `GET /auth/session` - Get session - `GET /auth/health` - Auth system health check ### Example Usage #### Register a new user ```bash curl -X POST http://localhost:3000/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "SecurePassword123!", "name": "John Doe" }' ``` Response: ```json { "success": true, "userId": "user_1234567890_abc123", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` #### Sign in ```bash curl -X POST http://localhost:3000/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "SecurePassword123!" }' ``` Response: ```json { "success": true, "userId": "user_1234567890_abc123", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` #### Connect to WebSocket with JWT ```javascript const ws = new WebSocket('ws://localhost:3000/ws/chat'); ws.addEventListener('open', () => { // Send auth token in initial message ws.send(JSON.stringify({ type: 'auth', token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' })); }); ``` Or use Authorization header: ```javascript const ws = new WebSocket('ws://localhost:3000/ws/chat', { headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' } }); ``` #### Get current session ```bash curl http://localhost:3000/auth/session \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` ## Passkey (WebAuthn) Support ### Server Setup Passkeys are automatically configured in `better-auth-config.ts`: ```typescript passkey({ rpName: 'Dexorder AI', rpID: new URL(config.baseUrl).hostname, origin: config.baseUrl, }) ``` ### Client-Side Integration ```typescript import { startRegistration, startAuthentication } from '@simplewebauthn/browser'; // 1. Register a passkey (user must be logged in) async function registerPasskey(token: string) { // Get options from server const optionsResponse = await fetch('/auth/passkey/register/options', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }); const options = await optionsResponse.json(); // Start WebAuthn registration const credential = await startRegistration(options); // Send credential to server const response = await fetch('/api/auth/passkey/register', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ credential }) }); return response.json(); } // 2. Authenticate with passkey async function authenticateWithPasskey() { // Get challenge from server const optionsResponse = await fetch('/api/auth/passkey/authenticate/options'); const options = await optionsResponse.json(); // Start WebAuthn authentication const credential = await startAuthentication(options); // Verify with server const response = await fetch('/auth/passkey/authenticate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ credential }) }); const { token, userId } = await response.json(); return { token, userId }; } ``` ## Multi-Channel Support ### WebSocket Authentication The WebSocket handler (`websocket-handler.ts`) now properly verifies JWT tokens: ```typescript // User connects with JWT token in Authorization header const authContext = await authenticator.authenticateWebSocket(request); // Returns: { userId, sessionId, license, ... } ``` ### Telegram Bot Authentication Users link their Telegram account via the `user_channel_links` table: ```sql INSERT INTO user_channel_links (user_id, channel_type, channel_user_id) VALUES ('user_1234567890_abc123', 'telegram', '987654321'); ``` The `authenticator.authenticateTelegram()` method resolves the user from their Telegram ID. ### API Authentication All REST API calls use the `Authorization: Bearer ` header. ## Security Considerations ### Production Checklist - [ ] Generate a strong random secret: `openssl rand -base64 32` - [ ] Enable email verification: Set `requireEmailVerification: true` - [ ] Configure HTTPS only in production - [ ] Set proper `trusted_origins` for CORS - [ ] Implement rate limiting (consider adding `@fastify/rate-limit`) - [ ] Set up email service for password reset - [ ] Configure session expiry based on security requirements - [ ] Enable 2FA for sensitive operations - [ ] Implement audit logging for auth events - [ ] Set up monitoring for failed login attempts ### Password Security - Uses **Argon2** (winner of Password Hashing Competition) - Automatically salted and hashed by Better Auth - Never stored or logged in plain text ### JWT Security - Tokens expire after 7 days (configurable) - Sessions update every 24 hours - Tokens signed with HMAC-SHA256 - Store secret in k8s secrets, never in code ### Passkey Security - Uses FIDO2/WebAuthn standards - Hardware-backed authentication - Phishing-resistant - No passwords to leak or forget ## Migration Guide If you have existing users with a different auth system: 1. **Create users in new schema:** ```sql INSERT INTO users (id, email, email_verified, name) SELECT user_id, email, true, name FROM old_users_table; ``` 2. **Migrate licenses:** ```sql -- Ensure user_licenses references users.id UPDATE user_licenses SET user_id = users.id WHERE ...; ``` 3. **User must reset password** or register passkey on first login with new system ## Troubleshooting ### "Authentication failed" on WebSocket - Check that the JWT token is valid and not expired - Verify the Authorization header format: `Bearer ` - Check server logs for detailed error messages ### "Invalid credentials" on login - Verify the user exists in the `users` table - Check that `user_credentials` has a password_hash for the user - Passwords are case-sensitive ### Passkey registration fails - Check browser support for WebAuthn - Verify HTTPS is enabled (required for WebAuthn in production) - Check `rpID` matches your domain - Ensure user is authenticated before registering passkey ## Development Tips ### Testing with dev user A development user is created automatically: ```javascript // Email: dev@example.com // User ID: dev-user-001 // License: pro ``` Generate a token for testing: ```bash curl -X POST http://localhost:3000/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"dev@example.com","password":""}' ``` ### Inspecting tokens ```bash # Decode JWT (header and payload only, signature verification needed) echo "eyJhbGc..." | cut -d. -f2 | base64 -d | jq ``` ### Database queries ```sql -- List all users SELECT id, email, name, created_at FROM users; -- List active sessions SELECT s.id, s.user_id, u.email, s.expires_at FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.expires_at > NOW(); -- List passkeys SELECT p.id, p.name, u.email, p.created_at FROM passkeys p JOIN users u ON p.user_id = u.id; ``` ## Future Enhancements Potential additions to consider: - [ ] OAuth providers (Google, GitHub, etc.) - [ ] Magic link authentication - [ ] Two-factor authentication (TOTP) - [ ] Session management dashboard - [ ] Audit log for security events - [ ] IP-based restrictions - [ ] Device management (trusted devices) - [ ] Anonymous authentication for trials ## References - [Better Auth Documentation](https://better-auth.com/) - [SimpleWebAuthn Guide](https://simplewebauthn.dev/) - [WebAuthn Guide](https://webauthn.guide/) - [FIDO Alliance](https://fidoalliance.org/) - [Fastify Authentication](https://fastify.dev/docs/latest/Guides/Getting-Started/#your-first-plugin)