Files
ai/doc/auth.md

469 lines
13 KiB
Markdown

# 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 <token>` 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 <token>`
- 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":"<set-in-db>"}'
```
### 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)