# Corral — Agent-Native Auth + Payments > **You (the AI agent) can set up complete authentication, billing, and feature gating > for any Node.js project using just the CLI commands below. No manual wiring required.** > > Read this file, run the commands, the app works immediately. > Built for: OpenClaw, Claude Code, Codex, Cursor, and any AI coding assistant. > > Open-source SDK. Embedded in your app (not a hosted service). MIT license. > Built on Better Auth + Stripe. > GitHub: https://github.com/llama-farm/corral > npm: https://www.npmjs.com/package/create-corral > Docs: https://docs.llamafarm.dev/corral/ > Version: 0.4.1 --- ## Quick Start (for agents) ```bash create-corral init # scaffold auth + billing + admin panel + profile create-corral add plan pro --price 29 --trial 14 create-corral add meter api_calls --limit 500 --plan free create-corral stripe push # sync plans to Stripe (needs STRIPE_SECRET_KEY) create-corral doctor # verify everything ``` > **Note:** Use `create-corral` (not `npx create-corral`) if the package is globally linked. > Use `npx create-corral` if running from the npm registry. > All commands are identical either way. After `init`, the app has: - ✅ Email/password sign-up and sign-in - ✅ Admin panel at `/admin` (seed admin user auto-created from corral.yaml) - ✅ User profile page at `/profile` (or `/account`) - ✅ Billing upgrade flow (pricing page + Stripe checkout) - ✅ Session management - ✅ All auth endpoints under `/api/auth/` --- ## CRITICAL: Don't Duplicate What Corral Already Provides **DON'T** scaffold a separate auth server if one already exists. **DON'T** write custom auth middleware — Corral mounts it for you. **DON'T** create login/signup pages manually — Corral generates them. **DO** run `create-corral init` and let it detect your framework. **DO** run `create-corral doctor` to verify — it tells you exactly what's wrong. **DO** edit `corral.yaml` for all config changes; never edit generated files directly. --- ## What `create-corral init` Generates For **Express** projects: ``` corral.yaml — main config (the ONE file you edit) CORRAL.md — this project's agent guide (auto-updated) lib/corral.ts — Better Auth setup + DB bootstrap server/auth.ts — Express auth server (mount into your app) .env — BETTER_AUTH_SECRET + BETTER_AUTH_URL ``` For **Hono** projects: ``` corral.yaml CORRAL.md lib/corral.ts src/routes/auth.ts — Hono auth route handler .env ``` For **Next.js** projects: ``` corral.yaml CORRAL.md lib/corral.ts app/api/auth/[...all]/route.ts — catch-all route handler .env.local ``` Files added by subsequent `add` commands: ``` app/api/webhooks/stripe/route.ts — from: corral add webhook app/device/verify/page.tsx — from: corral add device-verify src/pages/.tsx — from: corral add page ``` --- ## For Monorepos / Projects with an Existing Server Corral **auto-detects** your existing Express or Hono server and mounts into it. It does NOT create a parallel server. It adds mount instructions to your existing one. Example: if you have `server/index.ts` with Express, Corral adds: ```typescript import { auth } from './lib/corral.js'; import { toNodeHandler } from 'better-auth/node'; const authHandler = toNodeHandler(auth); app.all('/api/auth/*', (req, res) => authHandler(req, res)); ``` --- ## CRITICAL: Express Route Syntax **Express 4 uses `/*` — NOT `/*splat`** (that is Express 5 syntax). ```typescript // ✅ CORRECT (Express 4) app.all('/api/auth/*', (req, res) => authHandler(req, res)); // ❌ WRONG (Express 5 only) app.all('/api/auth/*splat', (req, res) => authHandler(req, res)); ``` If you see `/*splat` anywhere in generated files, replace it with `/*`. --- ## corral.yaml — The Config File Everything is controlled from `corral.yaml`. Edit this file, not the generated TypeScript. ```yaml app: name: MyApp id: myapp domain: http://localhost:3000 database: adapter: sqlite # sqlite | pg | mysql | turso | d1 url: ./corral.db auto_migrate: true auth: methods: email_password: true # google: true # Add providers with: corral add provider google # github: true plans: [] # Start empty; use: corral add plan --price # Example after adding plans: # - name: free # display_name: Free # price: 0 # features: [Everything in free] # cta: Get Started # - name: pro # display_name: Pro # price: 29 # interval: month # trial_days: 14 # stripe_price_id: price_xxx # auto-filled by: corral stripe push # features: [Unlimited access, Priority support] # cta: Start Free Trial features: {} # feature_name: ["plan1", "plan2"] # who can access this feature # browse: ["*"] # anyone including anonymous # export: ["pro", "team"] # pro and team plans only billing: provider: stripe currency: usd cancel_behavior: end_of_period meters: {} # meter_name: # label: Human Label # unit: requests # type: cap # reset_period: month # month | day # limits: # free: 100 # pro: 10000 # warning_at: 0.8 seed: admin: email: admin@example.com password: admin123 name: Admin # test_users: # - email: user@example.com # password: test123 # plan: pro admin: path: /admin require_role: admin ``` --- ## CLI Commands All commands accept `--json` for structured output and `--help` for details. ### Setup Commands ```bash create-corral analyze [--json] # detect framework/database (read-only) create-corral init [--db sqlite|pg|mysql|turso|d1] [--server express|hono] create-corral doctor # deep health check: config + env + deps + DB create-corral status [--json] # show users, plans, MRR, Stripe status ``` ### Add Commands (all idempotent — safe to run multiple times) ```bash # Plans create-corral add plan \ --price # monthly price in USD (required) [--trial ] # free trial days [--cta ] # button text (default: "Subscribe" or "Start Free Trial") [--features ] # comma-separated feature bullet points [--highlighted] # mark as popular/recommended # Features (access control) create-corral add feature --plan # --plan accepts comma-separated: --plan "pro,team" # Usage meters create-corral add meter --limit --plan # Or shorthand for common plan names: create-corral add meter --free --pro --team # Pages create-corral add page [--gated ] # Creates app//page.tsx (Next.js) or src/pages/.tsx (SPA) # Auth providers create-corral add provider google # also: github, discord, apple, microsoft, twitter # Other create-corral add webhook # Stripe webhook handler create-corral add device-verify # CLI device auth page (RFC 8628) create-corral add admin-page # admin dashboard page ``` ### Stripe ```bash create-corral stripe push [--json] # Reads corral.yaml plans, creates/finds Stripe products + prices, # writes stripe_price_id back to corral.yaml. # Requires: STRIPE_SECRET_KEY env var (sk_test_... or sk_live_...) # Skips free plans (price: 0). # Idempotent: safe to run multiple times. ``` ### Development ```bash create-corral seed # seed database with users from corral.yaml seed config create-corral dev # start standalone auth dev server create-corral rollback [--list] # undo last init/add operation ``` --- ## Doctor — What It Checks `create-corral doctor` verifies: - `corral.yaml` exists and parses without errors - Required env vars are set (`BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`) - All npm deps are installed (`better-auth`, `@llamafarm/corral`, database driver) - Database is reachable and tables exist - Stripe key is valid (if billing configured) - Plans with prices have `stripe_price_id` set - Auth endpoints respond (GET `/api/auth/ok` → 200) Run `doctor` after `init` and after any major change. Fix everything it reports. --- ## Admin User — Auto-Seeded On first server boot, Corral reads `corral.yaml` → `seed.admin` and creates the admin user automatically. No manual `INSERT` needed. ```yaml seed: admin: email: admin@yourapp.com password: yourpassword name: Admin ``` The admin user gets `role: admin` and can access the admin panel at `/admin`. --- ## After `init` — How to Test 1. **Sign up:** POST `/api/auth/sign-up/email` `{ email, password, name }` or visit the generated signup page 2. **Sign in:** POST `/api/auth/sign-in/email` `{ email, password }` 3. **Admin panel:** visit `/admin` (signed in as the seed admin) 4. **Profile page:** visit `/profile` or `/account` 5. **Upgrade flow:** visit the pricing page → click a plan → Stripe checkout 6. **Health check:** GET `/api/auth/ok` → `{ ok: true }` --- ## HTTP API Reference Base paths: `/api/auth` (Better Auth) and `/api/corral` (billing/device/usage) ### Auth - `POST /api/auth/sign-up/email` — `{ email, password, name }` - `POST /api/auth/sign-in/email` — `{ email, password }` - `POST /api/auth/sign-out` - `GET /api/auth/get-session` — returns user + session - `GET /api/auth/ok` — health check → `{ ok: true }` - `GET /api/auth/sign-in/social?provider=google&callbackURL=/` ### Billing - `POST /api/corral/checkout` — `{ planId }` → `{ url }` (Stripe checkout) - `GET /api/corral/billing` — subscription + invoices - `POST /api/corral/cancel` — cancel at period end - `POST /api/corral/reactivate` — undo cancel - `GET /api/corral/subscription/status` — `{ plan, role }` ### Usage Meters - `POST /api/corral/usage/track` — `{ meterId, count }` — increment - `GET /api/corral/usage/:meterId` — `{ used, limit, remaining, resetAt }` - `GET /api/corral/usage` — all meters for current user ### Device Auth (CLI → browser OAuth2, RFC 8628) - `POST /api/corral/device/authorize` → `{ deviceCode, userCode, verificationUrl }` - `POST /api/corral/device/token` — `{ deviceCode }` → poll until approved - `POST /api/corral/device/verify` — `{ userCode, action: "approve" }` (browser) - `POST /api/corral/device/refresh` — `{ refreshToken }` → new tokens ### API Keys - `POST /api/corral/apikeys` — `{ name }` → `{ id, key, prefix }` (key shown once) - `GET /api/corral/apikeys` — list (prefix only, not full key) - `DELETE /api/corral/apikeys/:id` — revoke ### Admin (requires role: admin) - `GET /api/auth/admin/list-users` — paginated user list --- ## Environment Variables ```env # Required BETTER_AUTH_SECRET= BETTER_AUTH_URL=http://localhost:3000 # Stripe (required for billing) STRIPE_SECRET_KEY=sk_test_... STRIPE_PUBLISHABLE_KEY=pk_test_... STRIPE_WEBHOOK_SECRET=whsec_... # OAuth providers (per provider) GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GITHUB_CLIENT_ID=... GITHUB_CLIENT_SECRET=... ``` --- ## Databases | Adapter | Driver Package | Notes | |---------|---------------|-------| | `sqlite` | `better-sqlite3` | Default. File-based. | | `pg` | `pg` | PostgreSQL | | `mysql` | `mysql2` | MySQL / MariaDB | | `turso` | `@libsql/client` | Turso / libSQL | | `d1` | built-in | Cloudflare D1 (edge) | Select with: `create-corral init --db ` --- ## Multi-Language Backend Session Validation Non-Node backends can validate Corral sessions via the shared database: - Python: `corral/validation/python/` — FastAPI/Flask/Django middleware - Go: `corral/validation/go/` — stdlib middleware - Rust: `corral/validation/rust/` — Axum extractor - Ruby: `corral/validation/ruby/` — Rack middleware These read the `session` + `user` tables directly. All auth writes go through the Node server. --- ## Deploy Generate deployment configs for your platform: ```bash corral deploy docker # Dockerfile + docker-compose + nginx + supervisord corral deploy fly # fly.toml + Dockerfile (--region iad) corral deploy railway # railway.json + Dockerfile corral deploy render # render.yaml + Dockerfile ``` Auto-detects backend language (Node/Python/Go/Rust/Ruby) and generates appropriate configs. --- ## More - Full docs: https://docs.llamafarm.dev/corral/ - GitHub: https://github.com/llama-farm/corral - npm: https://www.npmjs.com/package/create-corral - License: MIT - Built by LlamaFarm 🦙