Appearance
Authentication Backend Implementation
Architecture
Authentication is handled by Better Auth integrated with AdonisJS. All auth routes are proxied through a single controller that converts between AdonisJS and Better Auth's Web API format.
Client Request → AdonisJS Router → BetterAuthController → Better Auth → Database/RedisKey Components
Better Auth Configuration (app/lib/auth.ts)
- Database: PostgreSQL connection pool
- Secondary Storage: Redis for session caching
- Authentication: Email/password with Argon2 hashing
- Organizations: Multi-tenant workspace support
- Sessions: 7-day expiry with 1-day update interval
Controller (app/controllers/better_auth_controller.ts)
Single handler that:
- Converts AdonisJS request → Web API Request
- Passes to Better Auth handler
- Converts Web API Response → AdonisJS response
Route Configuration (start/routes.ts)
typescript
// All auth routes handled by Better Auth
router.any('/auth/*', [BetterAuthController, 'handle'])Data Models
User Model
typescript
class User {
id: string // UUID primary key
name: string | null // Display name
email: string // Login identifier
emailVerified: boolean // Email verification status
image: string | null // Profile image URL
createdAt: DateTime
updatedAt: DateTime
}Session Model
typescript
class Session {
id: string // Session token
userId: string // User reference
expiresAt: DateTime // Session expiry
ipAddress: string | null // Client IP
userAgent: string | null // Client info
activeOrganizationId: string | null // Current workspace
createdAt: DateTime
updatedAt: DateTime
}Organization Models
typescript
class Organization {
id: string // UUID
ownerId: string // User who created it
name: string // Organization name
slug: string // URL slug
logo: string | null // Logo URL
metadata: string | null // Additional data
}
class Member {
id: string // Membership record
userId: string // User reference
organizationId: string // Organization reference
role: string // Role (admin, member, etc.)
teamId: string | null // Optional team assignment
}Security Implementation
Password Security
- Hashing: Argon2 (industry standard)
- Verification: Constant-time comparison
- No plaintext storage: Passwords never stored unhashed
Session Security
- HTTP-only cookies: JavaScript cannot access tokens
- Secure cookies: HTTPS-only in production
- Cross-subdomain: Works across app/api subdomains
- Rate limiting: Built-in protection against brute force
Database Security
- UUID primary keys: No sequential ID leaking
- Connection pooling: Efficient database connections
- Prepared statements: SQL injection protection
Redis Configuration
Used for session caching and secondary storage:
typescript
secondaryStorage: {
get: async (key) => redis.get(key),
set: async (key, value, ttl) => redis.set(key, value, 'EX', ttl),
delete: async (key) => redis.del(key)
}Benefits:
- Fast session lookup: No database hit for every request
- Automatic expiry: TTL-based session cleanup
- Scalability: Shared state across multiple server instances
Organization Features
Multi-tenancy
- Users can belong to multiple organizations
- Each session tracks active organization
- Role-based permissions per organization
Invitation System
- Organization owners can invite users by email
- Pending invitations stored in database
- Email integration ready (TODO: implement email sending)
Team Support
- Teams are sub-groups within organizations
- Users can be assigned to specific teams
- Enables department/project-based organization
Environment Configuration
Required environment variables:
bash
# Database
DB_HOST=localhost
DB_PORT=5433
DB_USER=jubiloop
DB_PASSWORD=password
DB_DATABASE=jubiloop
# Server
SERVER_URL=https://api.jubiloop.localhost
DOMAIN=jubiloop.localhost
# Security
ALLOWED_ORIGINS=https://app.jubiloop.localhost,https://jubiloop.localhostAPI Endpoints
All authentication endpoints are prefixed with /auth/ and handled by Better Auth:
POST /auth/sign-up- User registrationPOST /auth/sign-in- User loginPOST /auth/sign-out- User logoutGET /auth/session- Get current session- Organization endpoints (managed by Better Auth plugin)
See API Reference for detailed endpoint documentation.
Database Naming Conventions
Better Auth is configured to use AdonisJS snake_case conventions:
email_verifiedinstead ofemailVerifiedcreated_atinstead ofcreatedAtuser_idinstead ofuserId
This ensures consistency with the rest of the AdonisJS application.
Future Enhancements
- Email verification: Currently disabled, can be enabled
- OAuth providers: Account model ready for Google/GitHub
- Two-factor auth: Better Auth supports TOTP
- Password reset: Email-based password recovery
- Audit logging: Track authentication events