Installation
bun add ideal-authnpm install ideal-authpnpm add ideal-authyarn add ideal-authSetup
-
Generate a secret
ideal-auth requires a secret of at least 32 characters for encrypting sessions and signing tokens. Generate one here or via the CLI:
Click "Generate" to create and copyClick "Generate" to create and copyOr use the CLI:
bunx ideal-auth secret # generates IDEAL_AUTH_SECRET bunx ideal-auth encryption-key # for encrypt()/decrypt() — optionalAdd the output to your environment variables:
.envbash IDEAL_AUTH_SECRET="your-generated-secret-here" -
Create the cookie bridge
The cookie bridge is what makes ideal-auth framework agnostic. It is an object with three functions —
get,set, anddelete— that tell ideal-auth how to interact with cookies in your framework.Here is a cookie bridge for Next.js (App Router):
lib/auth.tsts import { cookies } from 'next/headers'; import { createAuth, createHash } from 'ideal-auth'; const cookieBridge = { async get(name: string) { const jar = await cookies(); return jar.get(name)?.value; }, async set(name: string, value: string, options: any) { const jar = await cookies(); jar.set(name, value, options); }, async delete(name: string) { const jar = await cookies(); jar.delete(name); }, }; -
Create the auth and hash instances
lib/auth.tsts import { db } from './db'; // your database client export const hash = createHash(); export const auth = createAuth({ secret: process.env.IDEAL_AUTH_SECRET!, cookie: cookieBridge, // Look up a user by ID (used to rehydrate sessions) resolveUser: async (id) => { return db.user.findUnique({ where: { id } }); }, // Look up a user by credentials (used by auth().attempt()) resolveUserByCredentials: async (credentials) => { return db.user.findUnique({ where: { email: credentials.email } }); }, // Provide the hash instance so attempt() can verify passwords hash, });createAuthreturns a factory function. Callauth()in each request to get a freshAuthInstancescoped to that request’s cookies. -
Implement login
app/login/actions.tsts 'use server'; import { auth } from '@/lib/auth'; import { redirect } from 'next/navigation'; export async function login(formData: FormData) { const email = formData.get('email') as string; const password = formData.get('password') as string; const success = await auth().attempt({ email, password }); if (!success) { return { error: 'Invalid email or password.' }; } redirect('/dashboard'); }The
attemptmethod strips the password from the credentials, passes the remaining fields toresolveUserByCredentials, then verifies the password hash automatically. -
Implement logout
app/logout/actions.tsts 'use server'; import { auth } from '@/lib/auth'; import { redirect } from 'next/navigation'; export async function logout() { await auth().logout(); redirect('/login'); } -
Protect routes with middleware
middleware.tsts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { auth } from '@/lib/auth'; export async function middleware(request: NextRequest) { const isAuthenticated = await auth().check(); if (!isAuthenticated) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } export const config = { matcher: ['/dashboard/:path*', '/settings/:path*'], };
Registering users
ideal-auth does not manage user creation — that is up to your application. Use the hash instance to hash passwords before storing them:
'use server';
import { auth, hash } from '@/lib/auth';
import { db } from '@/lib/db';
import { redirect } from 'next/navigation';
export async function register(formData: FormData) {
const email = formData.get('email') as string;
const password = formData.get('password') as string;
const hashedPassword = await hash.make(password);
const user = await db.user.create({
data: { email, password: hashedPassword },
});
// Log the user in immediately after registration
await auth().login(user);
redirect('/dashboard');
}Reading the current user
Use auth().user() to get the full user object, or auth().id() to get just the user ID:
const currentUser = await auth().user(); // TUser | null
const userId = await auth().id(); // string | nullNext steps
- Configuration — All configuration options in detail
- Two-Factor Authentication — Add TOTP 2FA to your app
- Rate Limiting — Protect login endpoints from brute force
- Security Model — Understand the security guarantees