Authentication
ChimerAI ships with a production-ready authentication system built on NextAuth.js v4 with support for Email/Password and up to three optional OAuth providers — GitHub, Google, and Facebook — all pre-wired to your Prisma database via a single CLI command.
Installation
npx chimerai add auth
The CLI immediately shows a provider-selection prompt:
? Select additional OAuth providers (Email/Password is always included):
◯ GitHub — Developer-focused apps
◯ Google — Business & consumer apps
◯ Facebook — Social & consumer apps
Select as many providers as you need (or none — Email/Password always works).
Files scaffolded
| File | Purpose |
|---|---|
app/api/auth/[...nextauth]/route.ts | NextAuth.js handler |
app/auth/signin/page.tsx | Login page (with OAuth buttons if providers selected) |
lib/auth.ts | authOptions config |
lib/auth/resolve-auth.ts | Dual-auth resolver (session + API key) |
lib/api-key-auth.ts | API key verification |
lib/api-protection.ts | Route-level auth middleware helper |
lib/audit.ts | Audit log helper |
lib/gdpr.ts | GDPR helper |
components/SessionProvider.tsx | Client-side SessionProvider wrapper |
types/next-auth.d.ts | Type extensions for Session, User, JWT |
app/api/user/profile/route.ts | User profile API |
app/api/user/data-export/route.ts | GDPR data export |
app/api/user/account/route.ts | GDPR account deletion |
prisma/seed.ts | Seed: demo user + 4 default RBAC roles |
Dependencies installed automatically:
next-auth ^4.24.10
bcryptjs ^3.0.0
@auth/prisma-adapter ^2.11.1
next-themes ^0.4.6
sonner ^2.0.3
OAuth Providers
GitHub
- Create an OAuth App at github.com/settings/developers
- Set the callback URL:
https://yourdomain.com/api/auth/callback/github - Add to
.env:
GITHUB_ID=your-client-id
GITHUB_SECRET=your-client-secret
The generated login page shows a dark Continue with GitHub button with the GitHub logo.
- Create OAuth 2.0 credentials at console.cloud.google.com
- Authorised redirect URI:
https://yourdomain.com/api/auth/callback/google - Add to
.env:
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
The Google provider is configured with prompt: 'consent' and access_type: 'offline' to force refresh token issuance on first login.
- Create an App at developers.facebook.com
- Add the Facebook Login product; set the redirect URI:
https://yourdomain.com/api/auth/callback/facebook - Add to
.env:
FACEBOOK_CLIENT_ID=your-app-id
FACEBOOK_CLIENT_SECRET=your-app-secret
⚠️ Facebook requires HTTPS and App Review for production. During development, add yourself as a test user in the Facebook App dashboard.
Environment Variables
The CLI auto-writes only the vars you need based on your provider selection:
# Always added
DATABASE_URL=file:./dev.db
NEXTAUTH_SECRET=<auto-generated>
NEXTAUTH_URL=http://localhost:3000
# GitHub (if selected)
GITHUB_ID=
GITHUB_SECRET=
# Google (if selected)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Facebook (if selected)
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
Login Page
The generated app/auth/signin/page.tsx adapts to the providers you selected:
- No OAuth selected — simple email + password form only
- OAuth selected — OAuth buttons appear above the form with an "Or continue with" divider:
- GitHub → dark button with GitHub SVG logo
- Google → white-border button with the Google colour logo
- Facebook →
#1877F2blue button with the Facebook logo
lib/auth.ts
The generated authOptions always includes CredentialsProvider for email/password. OAuth providers are added conditionally based on your selection:
import GithubProvider from 'next-auth/providers/github';
import GoogleProvider from 'next-auth/providers/google';
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma) as any,
providers: [
GithubProvider({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: {
params: { prompt: 'consent', access_type: 'offline', response_type: 'code' },
},
}),
CredentialsProvider({
/* email + password with bcrypt */
}),
],
session: { strategy: 'jwt' },
pages: { signIn: '/auth/signin' },
};
The callbacks.jwt and callbacks.session blocks propagate the user's RBAC roles into the session token and session object. A signIn event logs every login to the audit trail.
Protecting Pages
// app/dashboard/page.tsx (Server Component)
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await getServerSession(authOptions);
if (!session) redirect('/auth/signin');
return <div>Hello {session.user?.name}</div>;
}
Protecting API Routes
// app/api/data/route.ts
import { resolveAuth } from '@/lib/auth/resolve-auth';
export async function GET(request: Request) {
const auth = await resolveAuth(request).catch(() => null);
if (!auth) return Response.json({ error: 'Unauthorized' }, { status: 401 });
// auth.userId, auth.email, auth.authMethod ('session' | 'api-key')
}
resolveAuth checks the NextAuth session first (browser users), then falls back to API key auth (widget / external integrations).
Prisma Schema
The auth component extends your schema with:
model User { id, email, password, name, ... accounts / sessions / apiKeys relations }
model Account { ... OAuth account data }
model Session { ... database sessions (required by PrismaAdapter even in JWT mode) }
model VerificationToken { ... }
model ApiKey { id, keyHash, userId, scopes, revoked, expiresAt }
Default Credentials
After running npx prisma db seed, a demo admin user is created:
| Field | Value |
|---|---|
admin@example.com | |
| Password | admin123 |
| Roles | All four default roles seeded: admin, power_user, user, readonly |