Auth Bootstrapper
I add production-ready BetterAuth authentication to Apso backends, giving you a fully functional authenticated REST API in under 5 minutes with zero manual steps.
Core Capabilities
1. setup-backend-with-auth
Complete backend setup from scratch with authentication
What I automate:
- •Create Apso backend project structure
- •Generate .apsorc with BetterAuth entities
- •Run
apso servercode generation - •Fix known integration issues automatically
- •Set up environment variables
- •Initialize database
- •Verify all endpoints work
- •Test authentication flows
Usage: "Setup backend with auth" or "Create new backend with authentication"
2. add-auth-to-existing
Add BetterAuth to existing Apso backend
What I automate:
- •Analyze current .apsorc schema
- •Detect and resolve entity naming conflicts
- •Add BetterAuth entities (User, account, session, verification)
- •Regenerate code with
apso server - •Fix DTO and entity issues
- •Update database schema
- •Configure auth endpoints
- •Test integration
Usage: "Add auth to my backend" or "Integrate BetterAuth"
3. fix-auth-issues
Auto-fix common BetterAuth integration problems
Issues I fix automatically:
- •Missing
idfield in DTOs - •Nullable field constraints
- •Entity naming conflicts
- •AppModule wiring issues
- •Database NOT NULL constraint errors
- •CORS configuration
- •Session cookie settings
Usage: "Fix auth issues" or "My auth isn't working"
4. verify-auth-setup
Run comprehensive verification checks
What I verify:
- •Database tables exist and are correct
- •All CRUD endpoints respond
- •User signup flow works
- •User signin flow works
- •Session creation works
- •Token validation works
- •Multi-tenancy isolation works
- •Organization auto-creation works
Usage: "Verify auth setup" or "Test the backend"
The 5-Minute Setup Process
When you say "setup backend with auth", I execute this fully automated workflow:
Phase 1: Project Initialization (30 seconds)
# 1. Create backend directory mkdir backend && cd backend # 2. Initialize Apso project npx apso init # 3. Install dependencies npm install
Phase 2: Schema Configuration (1 minute)
I create .apsorc with:
BetterAuth Required Entities:
- •
User(PascalCase) - Authentication user entity - •
account(lowercase) - OAuth/credential providers - •
session(lowercase) - Active user sessions - •
verification(lowercase) - Email verification tokens
Business Entities (renamed to avoid conflicts):
- •
Organization(NOT "Account") - Multi-tenant root - •
DiscoverySession(NOT "Session") - Your business sessions - •Junction tables for relationships
Critical Configuration Points:
{
"service": "your-backend",
"database": {
"provider": "postgresql",
"multiTenant": true,
"tenantKey": "account_id"
},
"entities": {
"User": {
"fields": {
"avatar_url": { "nullable": true }, // ← MUST be nullable
"password_hash": { "nullable": true }, // ← MUST be nullable
"oauth_provider": { "nullable": true }, // ← MUST be nullable
"oauth_id": { "nullable": true } // ← MUST be nullable
}
}
}
}
See references/apsorc-templates/ for complete examples.
Phase 3: Code Generation (30 seconds)
# Generate NestJS backend apso server # This creates: # - REST API controllers # - TypeORM entities # - DTOs with validation # - Service layer # - OpenAPI docs
Phase 4: Automatic Fixes (1 minute)
I apply these fixes automatically (no manual intervention):
Fix 1: Add id to Create DTOs
// backend/src/autogen/User/dtos/User.dto.ts
export class UserCreate {
@ApiProperty()
@IsUUID()
id: string; // ← I add this automatically
// ... rest of fields
}
Fix 2: Verify Nullable Fields
// backend/src/autogen/User/User.entity.ts
@Column({ nullable: true }) // ← I verify this is set
avatar_url: string;
@Column({ nullable: true }) // ← I verify this is set
password_hash: string;
Fix 3: AppModule Wiring
// backend/src/app.module.ts // I ensure all auth modules are imported imports: [ UserModule, AccountModule, SessionModule, VerificationModule, OrganizationModule, // ... ]
Phase 5: Environment Setup (30 seconds)
I create .env files:
# .env.development NODE_ENV=development PORT=3001 # Database DATABASE_URL=postgresql://postgres:postgres@localhost:5433/backend_dev # BetterAuth (I generate secure secrets) BETTER_AUTH_SECRET=generated-32-char-secret BETTER_AUTH_URL=http://localhost:3001 # CORS ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3003
Phase 6: Database Initialization (1 minute)
# Start PostgreSQL via Docker docker-compose up -d # Run migrations (TypeORM sync) npm run start:dev # Verify tables created psql -U postgres -d backend_dev -c "\dt"
Expected tables:
- •
user - •
account - •
session - •
verification - •
organization - •
account_user
Phase 7: Verification & Testing (1 minute)
I run these tests automatically:
Test 1: Server Health
curl http://localhost:3001/health
# Expected: {"status": "ok"}
Test 2: User Signup
curl -X POST http://localhost:3001/Users \
-H "Content-Type: application/json" \
-d '{
"id": "generated-uuid",
"email": "test@example.com",
"name": "Test User",
"email_verified": false
}'
# Expected: User object with ID
Test 3: Database Verification
SELECT id, email, name, email_verified FROM "user"; SELECT id, "userId", "providerId" FROM account; SELECT COUNT(*) FROM organization;
Test 4: CRUD Operations
# GET all users
curl http://localhost:3001/Users
# GET user by ID
curl http://localhost:3001/Users/{id}
# UPDATE user
curl -X PATCH http://localhost:3001/Users/{id} \
-d '{"name": "Updated Name"}'
# DELETE user
curl -X DELETE http://localhost:3001/Users/{id}
Complete .apsorc Templates
I provide ready-to-use templates in references/apsorc-templates/:
1. minimal-auth.json
Use for: Simple apps with just authentication Includes: User, account, session, verification, Organization
2. saas-platform.json
Use for: Full SaaS with multi-tenancy Includes: Auth + Organization + Projects + Billing + Audit logs
3. marketplace.json
Use for: Multi-vendor platforms Includes: Auth + Vendors + Products + Orders + Reviews
4. collaboration-tool.json
Use for: Team collaboration apps Includes: Auth + Workspaces + Channels + Messages + Files
Common Issues I Auto-Fix
Issue 1: "null value in column 'avatar_url' violates not-null constraint"
What I do:
- •Check
User.entity.tsfor nullable settings - •Update to
@Column({ nullable: true }) - •Drop and recreate database schema
- •Verify with test insert
Script: references/fix-scripts/fix-nullable-fields.sh
Issue 2: "null value in column 'id' of relation 'account'"
What I do:
- •Add
idfield toaccountCreateDTO - •Add
idfield toUserCreateDTO - •Add
@IsUUID()validator - •Regenerate OpenAPI docs
Script: references/fix-scripts/fix-dto-id-fields.sh
Issue 3: "Entity 'Account' conflicts with Better Auth"
What I do:
- •Detect conflict in .apsorc parsing
- •Rename
Account→Organization - •Update all foreign key references
- •Update entity descriptions
- •Regenerate code
Script: references/fix-scripts/fix-entity-conflicts.sh
Issue 4: "AppModule doesn't import auth entities"
What I do:
- •Parse AppModule imports
- •Add missing module imports
- •Verify module wiring
- •Test module loading
Script: references/fix-scripts/fix-app-module.sh
Environment Variables Management
I manage these environment files:
.env.development
NODE_ENV=development PORT=3001 DATABASE_URL=postgresql://postgres:postgres@localhost:5433/backend_dev BETTER_AUTH_SECRET=dev-secret-min-32-chars BETTER_AUTH_URL=http://localhost:3001 ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3003 LOG_LEVEL=debug
.env.test
NODE_ENV=test PORT=3002 DATABASE_URL=postgresql://postgres:postgres@localhost:5433/backend_test BETTER_AUTH_SECRET=test-secret-min-32-chars LOG_LEVEL=error
.env.production (template)
NODE_ENV=production
PORT=3001
DATABASE_URL=${DATABASE_URL} # From AWS RDS
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} # From AWS Secrets Manager
BETTER_AUTH_URL=https://api.yourdomain.com
ALLOWED_ORIGINS=https://yourdomain.com
LOG_LEVEL=info
Verification Checklist
Before marking setup as complete, I verify:
Backend Services:
- • Server starts without errors (port 3001)
- • Database connection successful
- • All tables created in database
- • OpenAPI docs accessible at /api/docs
- • Health endpoint returns 200
Entity Endpoints:
- • GET /Users returns 200
- • POST /Users creates user
- • GET /accounts returns 200
- • GET /sessions returns 200
- • GET /verifications returns 200
- • GET /Organizations returns 200
Authentication Flow:
- • User signup creates user + account
- • User signin validates credentials
- • Session creation works
- • Token validation works
- • Password hashing works
Multi-Tenancy (via scopeBy):
- • Organization auto-created on signup
- • User-Organization link created
- • Queries scoped to organizationId via ScopeGuard
- • Cross-tenant access blocked by scope verification
Data Integrity:
- • Foreign keys enforced
- • Unique constraints work
- • Nullable fields accept null
- • Required fields reject null
- • Enums validate values
Generated API Documentation
After setup, you get interactive docs at http://localhost:3001/api/docs
Endpoints per entity:
- •
GET /{entity}- List all (paginated, filtered) - •
GET /{entity}/{id}- Get by ID - •
POST /{entity}- Create new - •
PUT /{entity}/{id}- Full update - •
PATCH /{entity}/{id}- Partial update - •
DELETE /{entity}/{id}- Delete
Built-in features:
- •Pagination:
?page=1&limit=10 - •Sorting:
?sort=created_at&order=desc - •Filtering:
?status=active - •Search:
?search=keyword - •Relations:
?include=organization,user
File Structure Created
backend/ ├── src/ │ ├── autogen/ # ⚠️ NEVER MODIFY - Auto-generated by Apso │ │ ├── User/ │ │ │ ├── User.entity.ts │ │ │ ├── User.controller.ts │ │ │ ├── User.service.ts │ │ │ └── dtos/User.dto.ts │ │ ├── account/ │ │ ├── session/ │ │ ├── verification/ │ │ ├── Organization/ │ │ └── guards/ # ⚠️ AUTO-GENERATED - Auth & scope guards │ │ ├── auth.guard.ts # AuthGuard for session validation │ │ ├── scope.guard.ts # ScopeGuard for multi-tenant data isolation │ │ ├── guards.module.ts # NestJS module for guards │ │ └── index.ts # Barrel exports │ │ │ ├── extensions/ # ✅ Your custom code (safe to modify) │ │ ├── auth/ │ │ │ ├── auth.decorator.ts │ │ │ └── auth.service.ts │ │ └── organization/ │ │ └── organization.hooks.ts │ │ │ ├── common/ │ │ ├── filters/ │ │ ├── interceptors/ │ │ └── pipes/ │ │ │ ├── app.module.ts │ └── main.ts │ ├── test/ │ ├── e2e/ │ │ ├── auth.e2e-spec.ts │ │ └── users.e2e-spec.ts │ └── unit/ │ ├── .apsorc # Schema definition ├── .env.development ├── .env.test ├── docker-compose.yml ├── package.json └── README.md
Important: Guards are now generated inside src/autogen/guards/ to clearly indicate they are auto-generated and should not be manually edited. All files in autogen/ are overwritten on every apso server scaffold run.
Troubleshooting Commands
I provide these commands for debugging:
# Check database connection npm run db:ping # View all tables npm run db:tables # Run migrations npm run db:migrate # Seed test data npm run db:seed # Reset database npm run db:reset # View logs npm run logs # Test all endpoints npm run test:e2e # Generate new migration npm run migration:generate -- -n AddAuthTables
CRITICAL: Better Auth Architecture
Understanding how Better Auth stores credentials is essential for debugging!
┌──────────────────────────────────────────────────────────────────────────┐
│ Better Auth Data Model │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ User table: account table: │
│ ┌────────────────┐ ┌─────────────────────────────┐ │
│ │ id │ │ id │ │
│ │ email │───────│ userId │ │
│ │ name │ 1:N │ providerId = "credential" │ ← CRITICAL! │
│ │ email_verified │ │ password (bcrypt hash) │ ← Password! │
│ │ avatar_url │ │ accountId │ │
│ └────────────────┘ └─────────────────────────────┘ │
│ │
│ KEY INSIGHT: Passwords are in the ACCOUNT table, NOT the User table! │
│ │
│ Sign-in flow: │
│ 1. Better Auth calls: findUserByEmail(email, { includeAccounts: true }) │
│ 2. Adapter returns user WITH accounts array populated │
│ 3. Better Auth finds: user.accounts.find(a => a.providerId === "credential")
│ 4. Password verified against account.password (bcrypt) │
│ │
│ If providerId is undefined/null → Login ALWAYS fails! │
│ │
└──────────────────────────────────────────────────────────────────────────┘
Why Signup Works But Login Fails
The most common issue is: signup succeeds but login fails with "Invalid email or password".
Root Cause: The account.providerId field is not being set to "credential" during account creation, OR the adapter isn't returning it correctly during user lookup.
Solution:
- •Use
@apso/better-auth-adapter@2.0.2or higher - •Ensure
.apsorchasproviderIdfield in account entity - •Verify database:
SELECT "providerId" FROM account;should show"credential"
Integration with Frontend
After backend setup, I guide you to:
- •
Install BetterAuth adapter in frontend (CRITICAL: use v2.0.2+):
bashcd frontend npm install better-auth @apso/better-auth-adapter@latest
- •
Configure auth client:
typescript// frontend/lib/auth.ts import { betterAuth } from 'better-auth'; import { createApsoAdapter } from '@apso/better-auth-adapter'; export const auth = betterAuth({ database: createApsoAdapter({ baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:3001', }), emailAndPassword: { enabled: true }, }); - •
Test end-to-end flow (BOTH signup AND login!):
- •Frontend signup → Backend creates user + account with providerId="credential"
- •Frontend signin → Backend validates via account.password (NOT user.password_hash!)
- •Frontend protected route → Backend validates token
Reference Documentation
All in references/:
- •
apsorc-templates/- Complete .apsorc examples - •
fix-scripts/- Automated fix scripts - •
verification-commands/- Test commands - •
troubleshooting/- Common issues & solutions - •
better-auth-integration.md- Complete auth guide
Success Metrics
Setup time: < 5 minutes from start to working API Manual steps: 0 (fully automated) Error rate: < 5% (auto-fixes handle most issues) Test coverage: 100% of CRUD endpoints verified
Ready to Start?
Just say:
- •"Setup backend with auth" - Complete new backend
- •"Add auth to backend" - Add to existing backend
- •"Fix auth issues" - Debug current setup
- •"Verify backend" - Run all checks
I'll handle everything automatically and show you exactly what's happening at each step.