ideal-auth
Auth primitives for the JS ecosystem. Zero framework dependencies. Inspired by Laravel's Auth and Hash facades.
Documentation
Provide a cookie bridge (3 functions) once during setup, and auth().login(user) just works — handles session creation, cookie encryption, and storage internally via iron-session.
Install
bun add ideal-auth
Generate Secrets
# IDEAL_AUTH_SECRET (required — used by createAuth)
bunx ideal-auth secret
# IDEAL_AUTH_SECRET=aLThikMgJKMBB5WZLE-lCaOQUdgPWU8BHRv99bkYaVY
# Encryption key (optional — used by encrypt/decrypt for data at rest)
bunx ideal-auth encryption-key
# ENCRYPTION_KEY=9546dd9fa461ce15f0aacd6e1b461b52
Copy the output into your .env file. IDEAL_AUTH_SECRET must be at least 32 characters. ENCRYPTION_KEY is only needed if you use encrypt()/decrypt() (e.g., encrypting TOTP secrets or access tokens at rest).
Quick Start
// lib/auth.ts
import { createAuth, createHash } from 'ideal-auth';
import { cookies } from 'next/headers';
import { db } from '@/lib/db';
export const hash = createHash({ rounds: 12 });
export const auth = createAuth({
secret: process.env.IDEAL_AUTH_SECRET!, // 32+ characters
cookie: {
get: async (name) => (await cookies()).get(name)?.value,
set: async (name, value, opts) => (await cookies()).set(name, value, opts),
delete: async (name) => (await cookies()).delete(name),
},
hash,
resolveUser: async (id) => {
return db.user.findUnique({ where: { id } });
},
resolveUserByCredentials: async (credentials) => {
return db.user.findUnique({ where: { email: credentials.email } });
},
});
// Server Action
'use server';
import { auth } from '@/lib/auth';
// Call auth() once per request and reuse the instance — it caches the
// session payload and user, so subsequent calls avoid redundant work.
const session = auth();
// Login with credentials (password verified automatically)
const success = await session.attempt({ email, password });
// Login with a user object directly
await session.login(user);
// Login by user ID
await session.loginById('user-123');
// Check session
const isLoggedIn = await session.check();
const currentUser = await session.user();
const userId = await session.id();
// Logout
await session.logout();
API
createAuth(config)
Returns a function auth(options?) that creates an AuthInstance on each call. Pass { autoTouch: true } to enable automatic session extension for that request.
const session = auth(); // default — read-only check/user/id
const session = auth({ autoTouch: true }); // auto-extends session past halfway on check/user/id
Config
| Field | Type | Required | Default |
|---|
secret | string | Yes | — |
cookie | CookieBridge | Yes | — |
resolveUser | (id: string) => Promise<User | null | undefined> | Yes (unless sessionFields is provided) | — |
sessionFields | (keyof User & string)[] | Yes (unless resolveUser is provided) | — |
hash | HashInstance | No | — |
resolveUserByCredentials | (creds: Record<string, any>) => Promise<AnyUser | null | undefined> | No | — |
credentialKey | string | No | 'password' |
passwordField | string | No | 'password' |
attemptUser | (creds: Record<string, any>) => Promise<User | null | undefined> | No | — |
session.cookieName | string | No | 'ideal_session' |
session.maxAge | number (seconds) | No | 604800 (7 days) |
session.rememberMaxAge | number (seconds) | No | 2592000 (30 days) |
session.autoTouch | boolean | No | false. Auto-extend sessions past halfway on check()/user()/id(). Enable for Express/Hono. Disable for Next.js. |
session.cookie | Partial<ConfigurableCookieOptions> | No | secure in prod, sameSite lax, path / (httpOnly is always true — not configurable) |
AuthInstance Methods
| Method | Returns | Description |
|---|
login(user, options?) | Promise<void> | Set session cookie for the given user |
loginById(id, options?) | Promise<void> | Resolve user by ID, then set session cookie |
attempt(credentials, options?) | Promise<boolean> | Find user, verify password, login if valid |
logout() | Promise<void> | Delete session cookie |
check() | Promise<boolean> | Is the session valid? (read-only) |
user() | Promise<SessionUser<User> | null> | Get the authenticated user (read-only). id is always string — see note on id types. |
id() | Promise<string | null> | Get the authenticated user's ID (read-only) |
touch() | Promise<void> | Extend session expiry. Reseals past halfway (autoTouch: false) or immediately (autoTouch: true). |