createAuth
Signature
Section titled “Signature”function createAuth<TUser>(config: AuthConfig<TUser>): () => AuthInstance<TUser>createAuth is the main entry point for session-based authentication. It accepts an AuthConfig object and returns a factory function. Each call to the factory produces an AuthInstance scoped to the current request’s cookies.
import { createAuth, createHash } from 'ideal-auth';
const hash = createHash();
const auth = createAuth({ secret: process.env.AUTH_SECRET!, cookie: cookieBridge, resolveUser: async (id) => db.user.findUnique({ where: { id } }), resolveUserByCredentials: async (creds) => db.user.findUnique({ where: { email: creds.email } }), hash,});
// In a request handler:const session = auth();const user = await session.user();AuthConfig
Section titled “AuthConfig”| Field | Type | Required | Default |
|---|---|---|---|
secret | string | Yes | — |
cookie | CookieBridge | Yes | — |
session.cookieName | string | No | 'ideal_session' |
session.maxAge | number (seconds) | No | 604800 (7 days) |
session.rememberMaxAge | number (seconds) | No | 2592000 (30 days) |
session.cookie | Partial<ConfigurableCookieOptions> | No | secure in production, sameSite: 'lax', path: '/' |
resolveUser | (id: string) => Promise<TUser | null> | Yes | — |
resolveUserByCredentials | (credentials: Record<string, unknown>) => Promise<TUser | null> | No | — |
hash | HashInstance | No | — |
credentialKey | string | No | 'password' |
passwordField | string | No | 'password' |
attemptUser | (credentials: Record<string, unknown>) => Promise<TUser | null> | No | — |
secret
Section titled “secret”A string of at least 32 characters used to encrypt session cookies. Generate one with the CLI:
bunx ideal-auth secretcookie
Section titled “cookie”A CookieBridge object that tells ideal-auth how to interact with cookies in your framework.
session
Section titled “session”Optional session configuration. The defaults work well for most applications.
cookieName— Name of the session cookie stored in the browser.maxAge— Lifetime of the session cookie in seconds. Used whenrememberis not specified in login options.rememberMaxAge— Lifetime of the session cookie in seconds whenremember: trueis passed to login.cookie— Partial cookie options merged with the defaults. You can overridesameSite,path,domain, andsecure. ThehttpOnlyflag is always forced totrueand cannot be overridden.
resolveUser
Section titled “resolveUser”Called when the session is read to hydrate the full user object from a user ID. Must return the user object or null if the user no longer exists.
resolveUser: async (id) => { return db.user.findUnique({ where: { id } });}resolveUserByCredentials
Section titled “resolveUserByCredentials”Used by attempt() in Laravel-style mode to look up a user by the non-password fields of the credentials object. The credentialKey field (default 'password') is stripped before the object is passed to this function.
resolveUserByCredentials: async (credentials) => { // credentials = { email: "user@example.com" } // (password was already stripped) return db.user.findUnique({ where: { email: credentials.email } });}A HashInstance created by createHash(). Required for the Laravel-style attempt() mode.
credentialKey
Section titled “credentialKey”The key in the credentials object that contains the password. Defaults to 'password'. This key is stripped from credentials before passing them to resolveUserByCredentials.
passwordField
Section titled “passwordField”The property name on the user object that stores the hashed password. Defaults to 'password'. Used by attempt() to read the stored hash for verification.
attemptUser
Section titled “attemptUser”A function for manual mode that receives the full credentials object and returns a user if authentication succeeds. Takes precedence over the Laravel-style flow if both are configured.
AuthInstance
Section titled “AuthInstance”The object returned by calling the factory function. All methods are async.
login(user: TUser, options?: LoginOptions): Promise<void>Sets the session cookie with the given user. The user object must have an id property (string).
const session = auth();const user = await db.user.findUnique({ where: { email } });
if (user) { await session.login(user);}loginById
Section titled “loginById”loginById(id: string, options?: LoginOptions): Promise<void>Resolves a user by ID using resolveUser, then sets the session cookie. Throws an error with the message 'Login failed' if the user is not found.
const session = auth();
try { await session.loginById('user_abc123');} catch (error) { // error.message === 'Login failed'}attempt
Section titled “attempt”attempt( credentials: Record<string, unknown>, options?: LoginOptions,): Promise<boolean>Finds a user by credentials, verifies the password, and logs the user in if valid. Returns true on success, false on failure. See Attempt Modes for details.
const session = auth();const success = await session.attempt({ email: 'user@example.com', password: 'correct-password',});
if (!success) { return { error: 'Invalid credentials.' };}logout
Section titled “logout”logout(): Promise<void>Deletes the session cookie, ending the user’s session.
const session = auth();await session.logout();check(): Promise<boolean>Returns true if the current request has a valid session with a resolvable user. Does not throw.
const session = auth();
if (await session.check()) { // user is authenticated}user(): Promise<TUser | null>Returns the authenticated user object or null if no valid session exists. The result is cached for the lifetime of the AuthInstance — subsequent calls return the same object without re-querying.
const session = auth();const currentUser = await session.user();
if (!currentUser) { redirect('/login');}id(): Promise<string | null>Returns the user ID from the session cookie or null if no valid session exists. This reads only the session cookie and does not call resolveUser.
const session = auth();const userId = await session.id();LoginOptions
Section titled “LoginOptions”interface LoginOptions { remember?: boolean;}Controls the lifetime of the session cookie set during login.
| Value | Behavior | Cookie maxAge |
|---|---|---|
true | Long-lived session | rememberMaxAge (default 30 days) |
false | Session cookie (browser close) | undefined (no maxAge) |
| omitted | Default session lifetime | maxAge (default 7 days) |
// "Remember me" checked — 30-day sessionawait session.login(user, { remember: true });
// "Remember me" unchecked — session ends when browser closesawait session.login(user, { remember: false });
// Default — 7-day sessionawait session.login(user);CookieBridge
Section titled “CookieBridge”interface CookieBridge { get(name: string): Promise<string | undefined> | string | undefined; set(name: string, value: string, options: CookieOptions): Promise<void> | void; delete(name: string): Promise<void> | void;}The cookie bridge is how ideal-auth interacts with your framework’s cookie API. Each method can be synchronous or asynchronous.
Next.js (App Router) example:
import { cookies } from 'next/headers';
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); },};Express example:
function createCookieBridge(req, res) { return { get(name: string) { return req.cookies[name]; }, set(name: string, value: string, options: any) { res.cookie(name, value, options); }, delete(name: string) { res.clearCookie(name); }, };}Attempt Modes
Section titled “Attempt Modes”The attempt() method supports two modes for resolving and verifying users.
Laravel-style mode
Section titled “Laravel-style mode”Provide hash and resolveUserByCredentials in the config. When attempt() is called:
- The
credentialKey(default'password') is stripped from the credentials object. - The remaining fields are passed to
resolveUserByCredentialsto look up the user. - The password is verified against
user[passwordField]using thehashinstance. - If verification succeeds, the user is logged in.
import { createAuth, createHash } from 'ideal-auth';
const hash = createHash();
const auth = createAuth({ secret: process.env.AUTH_SECRET!, cookie: cookieBridge, resolveUser: async (id) => db.user.findUnique({ where: { id } }), resolveUserByCredentials: async (credentials) => { // credentials = { email: "user@example.com" } return db.user.findUnique({ where: { email: credentials.email } }); }, hash, // credentialKey: 'password', // default // passwordField: 'password', // default});
// Usageconst success = await auth().attempt({ email: 'user@example.com', password: 'their-password',});Manual mode
Section titled “Manual mode”Provide attemptUser for full control over credential resolution and password verification. This takes precedence over the Laravel-style flow if both are configured.
import { createAuth, createHash } from 'ideal-auth';
const hash = createHash();
const auth = createAuth({ secret: process.env.AUTH_SECRET!, cookie: cookieBridge, resolveUser: async (id) => db.user.findUnique({ where: { id } }), attemptUser: async (credentials) => { const user = await db.user.findUnique({ where: { email: credentials.email as string }, });
if (!user) return null;
const valid = await hash.verify( credentials.password as string, user.password, );
return valid ? user : null; },});
// Usage is identicalconst success = await auth().attempt({ email: 'user@example.com', password: 'their-password',});All types are available as type-only exports:
import type { AuthConfig, AuthInstance, CookieBridge, CookieOptions, ConfigurableCookieOptions, LoginOptions,} from 'ideal-auth';