Skip to main content

🚀 Demo server

Want to try it without any setup?

→ Open the Live Interactive Demo — register, login, and explore the API right in your browser. No installation needed.

A complete, self-contained Express server you can run locally in under two minutes.
No database. No cloud. No environment variables to configure — just copy, install, and go.

Data resets on restart

This demo uses in-memory storage. All registered users vanish when the server stops — perfect for exploring the library without any setup.


1 · Install dependencies

npm install awesome-node-auth express cookie-parser
npm install -D typescript ts-node @types/node @types/express @types/cookie-parser

2 · Complete demo server

Save the file below as server.ts and run it — everything is self-contained.

import express from 'express';
import cookieParser from 'cookie-parser';
import {
AuthConfigurator,
createAdminRouter,
PasswordService,
IUserStore,
BaseUser,
ISettingsStore,
AuthSettings,
} from 'awesome-node-auth';

// ── 1. In-memory user store ───────────────────────────────────────────────────
// Stores users in a plain Map<string, BaseUser>.
// All data is lost when the server restarts — do not use in production.

class InMemoryUserStore implements IUserStore {
private users = new Map<string, BaseUser>();
private nextId = 1;

async findByEmail(email: string) {
return [...this.users.values()].find(u => u.email === email) ?? null;
}
async findById(id: string) { return this.users.get(id) ?? null; }

async create(data: Partial<BaseUser>): Promise<BaseUser> {
const id = String(this.nextId++);
const user: BaseUser = { id, email: data.email ?? '', ...data };
this.users.set(id, user);
return user;
}

async updateRefreshToken(id: string, token: string | null, expiry: Date | null) {
const u = this.users.get(id);
if (u) { u.refreshToken = token; u.refreshTokenExpiry = expiry; }
}
async updateLastLogin(id: string) {
const u = this.users.get(id); if (u) u.lastLogin = new Date();
}
async updateResetToken(id: string, token: string | null, expiry: Date | null) {
const u = this.users.get(id);
if (u) { u.resetToken = token; u.resetTokenExpiry = expiry; }
}
async updatePassword(id: string, hashed: string) {
const u = this.users.get(id); if (u) u.password = hashed;
}
async updateTotpSecret(id: string, secret: string | null) {
const u = this.users.get(id);
if (u) { u.totpSecret = secret; u.isTotpEnabled = secret !== null; }
}
async updateMagicLinkToken(id: string, token: string | null, expiry: Date | null) {
const u = this.users.get(id);
if (u) { u.magicLinkToken = token; u.magicLinkTokenExpiry = expiry; }
}
async updateSmsCode(id: string, code: string | null, expiry: Date | null) {
const u = this.users.get(id);
if (u) { u.smsCode = code; u.smsCodeExpiry = expiry; }
}

// Required for the admin panel users table and user deletion:
async listUsers(limit: number, offset: number) {
return [...this.users.values()].slice(offset, offset + limit);
}
async deleteUser(id: string) { this.users.delete(id); }
}

// ── 2. In-memory settings store ───────────────────────────────────────────────
// Enables the ⚙️ Control tab in the admin panel (email verification policy,
// mandatory 2FA toggle, lazy grace-period days, etc.).

class InMemorySettingsStore implements ISettingsStore {
private settings: AuthSettings = {};
async getSettings() { return { ...this.settings }; }
async updateSettings(updates: Partial<AuthSettings>) {
this.settings = { ...this.settings, ...updates };
}
}

// ── 3. Wire everything together ───────────────────────────────────────────────

const app = express();
app.use(express.json());
app.use(cookieParser()); // needed to read/write JWT cookies

const userStore = new InMemoryUserStore();
const settingsStore = new InMemorySettingsStore();
const passwordService = new PasswordService();

const config = {
accessTokenSecret: 'demo-access-secret-change-in-production',
refreshTokenSecret: 'demo-refresh-secret-change-in-production',
accessTokenExpiresIn: '15m',
refreshTokenExpiresIn: '7d',
cookieOptions: { secure: false, sameSite: 'lax' as const },
};

const auth = new AuthConfigurator(config, userStore);

// ── 4. Auth routes ────────────────────────────────────────────────────────────
// POST /auth/register — create a new account
// POST /auth/login — email + password → sets HttpOnly JWT cookies
// GET /auth/me — return the authenticated user's profile
// POST /auth/logout — clear JWT cookies
// POST /auth/refresh — rotate the access token using the refresh cookie

app.use('/auth', auth.router({
onRegister: async (data) => {
const hashed = await passwordService.hash(data.password as string);
return userStore.create({
email: data.email as string,
password: hashed,
role: 'user',
});
},
}));

// ── 5. A custom protected route ───────────────────────────────────────────────
// auth.middleware() verifies the access-token cookie (or Bearer header).
// req.user contains { sub, email, role, ... } from the JWT payload.

app.get('/profile', auth.middleware(), (req, res) => {
res.json({ message: 'You are authenticated!', user: req.user });
});

// ── 6. Admin panel ────────────────────────────────────────────────────────────
// Browse to http://localhost:3000/admin and enter the password below.
// The built-in UI lets you list/delete users and tweak auth settings.

app.use('/admin', createAdminRouter(userStore, {
adminSecret: '1234', // ← change this in production!
settingsStore,
}));

// ── 7. Start ──────────────────────────────────────────────────────────────────

app.listen(3000, () => {
console.log('');
console.log(' Demo running → http://localhost:3000');
console.log(' Admin panel → http://localhost:3000/admin (password: 1234)');
console.log('');
});

3 · Run it

npx ts-node server.ts

4 · Available endpoints

MethodPathAuth requiredDescription
POST/auth/registerRegister a new user (email + password in body)
POST/auth/loginLogin → sets accessToken + refreshToken HttpOnly cookies
GET/auth/meReturn the authenticated user's profile
POST/auth/logoutClear the JWT cookies
POST/auth/refreshRotate the access token using the refresh cookie
GET/profileCustom protected route example
GET/adminAdmin panel UI (password: 1234)

5 · Try it with curl

Register an account:

curl -c cookies.txt -s -X POST http://localhost:3000/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"secret123"}' | jq

Login:

curl -c cookies.txt -s -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"secret123"}' | jq

Fetch your profile (reads the saved cookies):

curl -b cookies.txt -s http://localhost:3000/auth/me | jq

Hit the custom protected route:

curl -b cookies.txt -s http://localhost:3000/profile | jq

Refresh tokens:

curl -b cookies.txt -c cookies.txt -s -X POST http://localhost:3000/auth/refresh | jq

Logout:

curl -b cookies.txt -c cookies.txt -s -X POST http://localhost:3000/auth/logout

6 · Admin panel

Open http://localhost:3000/admin in your browser.

When the login dialog appears enter:

Password: 1234

The built-in admin dashboard gives you:

  • 👤 Users tab — list all registered users, view details, delete accounts
  • ⚙️ Control tab — toggle email verification policy (none / lazy / strict), enforce mandatory 2FA globally

Production checklist

Before going live replace every placeholder with real values:

# Use strong random secrets (e.g. openssl rand -hex 32)
ACCESS_TOKEN_SECRET=...
REFRESH_TOKEN_SECRET=...
ADMIN_SECRET=...

Also set cookieOptions.secure: true and sameSite: 'strict' (or 'none' for cross-origin with HTTPS).