Quick Start

Quick Start

A full OTP login flow in three steps. No configuration is required to try it - in development guardo creates a throwaway Ethereal test inbox and prints a preview URL for each email (falling back to the console if Ethereal is unreachable).

auth.ts
import { createAuth } from "guardo";
 
const auth = createAuth({
  jwt: { secret: process.env.JWT_SECRET! }, // must be at least 16 characters
});
 
// ─── Step 1: Send OTP ─────────────────────────────────────
await auth.otp.send({ identifier: "user@example.com" });
// β†’ OTP delivered to inbox (preview URL printed in dev)
 
// ─── Step 2: Verify OTP + login ───────────────────────────
const { user, accessToken, refreshToken, sessionId } =
  await auth.auth.loginWithOtp({
    identifier: "user@example.com",
    otp: "123456",
    meta: { device: "chrome-mac", ip: req.ip },
  });
 
// ─── Step 3: Protect routes ──────────────────────────────
app.get("/me", auth.middleware.express(), (req, res) => {
  // Without `resolveUser`, req.user is the decoded JWT payload:
  // { sub, email?, sessionId?, type, iat, exp }
  res.json(req.user);
});
⚠️

By default req.user is the decoded token payload (sub, email?, sessionId, type, iat, exp) - not the user object returned by loginWithOtp(). Configure resolveUser to make req.user your full User instead.

Want OTPs in your terminal instead of an email inbox? Pass notifier: new ConsoleNotifier() to createAuth(). See Notifiers.

What just happened

Send

auth.otp.send() generated a 6-digit code, stored only its SHA-256 hash, and delivered it through the configured notifier.

Verify & log in

auth.auth.loginWithOtp() verified the code, resolved (or auto-provisioned) the user, created a session, and issued an access + refresh token pair.

Protect

auth.middleware.express() validated the Authorization: Bearer header on every request, attached req.user and req.session, and refreshed the session’s lastActiveAt.

Next steps

  • Configuration - tune TTLs, rate limits, storage, and more
  • Auth Module - refresh tokens and logout
  • Events - hook into the auth lifecycle for audit logging