Skip to contentSkip to navigation

Quickstart

Get your first login working in under five minutes. You need Node.js 18+ and a Postgres database.

Install

bash
npm install own-auth

Set Your Environment Variables

Add your Postgres connection string and token pepper to your environment.

.env
DATABASE_URL=postgres://user:password@localhost:5432/myapp
OWN_AUTH_TOKEN_PEPPER=your-random-secret-string

The token pepper adds an extra layer of protection to hashed tokens in your database. Generate a long random string and keep it secret.

Any Postgres database works: local, hosted, Supabase, Neon, Railway, or RDS. Own Auth creates its own tables and does not modify yours.

Run Migrations

bash
npx own-auth migrate

This creates the tables Own Auth needs: users, sessions, tokens, organisations, API keys, and audit logs. Your existing tables are not modified.

Run this once during setup.

Verify the database connection and migration version:

bash
npx own-auth status

Create Your Auth Instance

Create an auth.ts file in your project. This is the single entry point for all auth operations.

auth.ts
import { createOwnAuth } from "own-auth";

export const auth = createOwnAuth({
  tokenPepper: process.env.OWN_AUTH_TOKEN_PEPPER,
  session: {
    ttlMs: 30 * 24 * 60 * 60 * 1000, // 30 days
  },
});

That is your auth layer. Every function in this guide is called on this auth instance. Own Auth reads DATABASE_URL automatically.

Sign Up A User

signup.ts
const { user, session, sessionToken } = await auth.signUpEmailPassword({
  email: "alice@example.com",
  password: "her-secret-password",
  name: "Alice",
});

// user.id           -> "usr_a1b2c3..."
// user.email        -> "alice@example.com"
// user.name         -> "Alice"
// sessionToken      -> send this to the client securely
// session.expiresAt -> 2026-08-09T...

The password is hashed before it is stored. Own Auth never saves plain-text passwords. The session is created automatically, so the user is signed in as soon as they sign up.

If the email is already taken, signUpEmailPassword throws a typed error you can catch and handle:

signup.ts
import { AuthError } from "own-auth";

try {
  const { user, session, sessionToken } = await auth.signUpEmailPassword({
    email,
    password,
    name,
  });
} catch (error) {
  if (error instanceof AuthError && error.code === "email_already_exists") {
    // Handle the duplicate email.
  }
  throw error;
}

Sign In

signin.ts
const { user, session, sessionToken } = await auth.signInEmailPassword({
  email: "alice@example.com",
  password: "her-secret-password",
});

// sessionToken      -> send this to the client securely
// session.userId    -> "usr_a1b2c3..."
// session.expiresAt -> 2026-08-09T...

The session token identifies the user on future requests. Send it to the client as a cookie, a header, or however your application handles tokens.

If the credentials are wrong, signInEmailPassword throws AuthError with the code invalid_credentials. The error deliberately does not reveal whether the email or password was wrong.

Verify A Session

On every authenticated request, verify the session token to identify the user.

session.ts
const result = await auth.getCurrentSession(sessionToken);

if (!result) {
  // Not signed in. Return 401.
}

// result.session.userId -> "usr_a1b2c3..."
// result.user            -> { id, email, name, ... }

getCurrentSession checks the token against the database. If the session is expired or has been revoked, it returns null.

Sign Out

ts
await auth.signOut(sessionToken);

The session is revoked immediately. The token stops working on the next request.

Full Example

Here is everything together in a minimal script. No framework, just plain TypeScript. Swap in Express, Hono, Fastify, or whatever you use.

server.ts
import { auth } from "./auth";

// Sign up.
const { sessionToken } = await auth.signUpEmailPassword({
  email: "alice@example.com",
  password: "her-secret-password",
  name: "Alice",
});

// Send sessionToken to the client as a cookie, header, or another secure value.

// Later, verify the session on an incoming request.
const result = await auth.getCurrentSession(sessionToken);

if (result) {
  console.log("Signed in as", result.user.email);
}

// Sign out.
await auth.signOut(sessionToken);

That is it. Users, passwords, and sessions are working. Everything is in your Postgres database, under your control.

What's Next

You have basic email/password auth. Here is where to go next:

Auth methods: Add passwordless login with magic links, or phone-based login with SMS verification.

Sessions: Learn how session management works, including revoking sessions across devices.

Organisations: Add teams, roles, and invitations for multi-tenant applications.

API access for integrations: Issue scoped application API keys for programmatic access to your application's API.

Email delivery: Set up your own email provider, or use Own Auth Delivery to send magic links, verification emails, and invitations without configuring SMTP.

Security: Read the security model to understand hashing, token expiry, rate limiting, and audit logs.

Framework guides: See integration guides for Next.js, Express, Hono, and Fastify.