Authentication Overview
User authentication system powered by Better Auth.
Overview
Cursorhero uses Better Auth for authentication, supporting email/password login and optional Google OAuth.
Supported Auth Methods
- Email + Password — Traditional registration with email verification
- Google OAuth — Optional social login via Google accounts
Registration Flow
- User submits name, email, and password
- Account is created with email verification pending
- No credit bonus on signup. New users start at zero credits and
instead get 3 free previews via
getRemainingPreviews()infeatures/cursor-generator/utils.ts(configured byFREE_PREVIEW_LIMITinfeatures/cursor-generator/constants.ts). Once those previews are used, the user must buy a one-time credit pack or subscribe to generate more. To restore the legacy 300-credit signup bonus, re-add the after hook inlib/auth.ts. - Verification email is sent via Resend
- User verifies email to unlock full access
Configuration
The auth configuration lives in lib/auth.ts:
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
},
...(process.env.AUTH_GOOGLE_ID && process.env.AUTH_GOOGLE_SECRET
? {
socialProviders: {
google: {
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
},
},
}
: {}),
});When the Google credentials are missing, the starter keeps email/password auth enabled and hides the Google button from the login and signup forms.
Session Management
- Sessions are stored in the
sessiontable - Session validation checks ban status (
isBanActive()) - Protected routes use
getActiveSessionUser()fromlib/auth/session.ts
Route Protection
| Route Group | Protection |
|---|---|
(protected) | Requires login — SessionGuard component |
(admin) | Requires role='admin' — AdminGuard component |
(auth) | Public — accessible without login |
(marketing) | Public |