SaaS
Next.js authentication architecture
Email and password sessions in the SaaS starter: a hashed password, a session cookie, and routes that refuse anonymous users.
The Complete SaaS Starter Kit and the Next.js SaaS Boilerplate both identify a user with an email, a password hash, and a session. Neither kit uses a third-party auth host. This page is that boundary, which the rest of building a SaaS with Next.js assumes is already true.
What is stored
The user row is small:
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
name String
plan String @default("free")
}
The password is stored as passwordHash, not the password. Signup hashes it before insert. Login loads the user by email and compares the hash. A failed compare does not create a session.
What the session is for
After a successful compare, the app sets a session that later routes can read. Checkout, the dashboard, and the billing page all refuse a request with no user. The Stripe customer id is written onto this same row later. See Stripe subscriptions with Next.js.
The boilerplate uses SQLite and the same user columns. The full kit uses PostgreSQL. The auth shape does not change with the database.
Do not put the plan decision in the client.
planchanges when the webhook runs, which is covered in synchronizing Stripe subscription state.