flexiguard
v1.0.0
Published
Ultra-flexible authentication library for modern frameworks. ORM-agnostic, Database-agnostic, Framework-agnostic.
Maintainers
Readme
✨ Features
- 🔐 Complete Auth — Register, login, logout, password reset, email verification
- 🎭 OAuth Providers — Google, GitHub, Facebook, Apple, custom providers
- 🔄 Session Management — Database sessions or stateless JWT
- 🛡️ Security First — Argon2 hashing, HMAC signing, CSRF protection
- 🔌 Any ORM — Prisma, Drizzle, Sequelize, Mongoose, Kysely, or custom
- 🗄️ Any Database — PostgreSQL, MySQL, SQLite, MongoDB, PlanetScale, Neon
- ⚡ Any Framework — Express, Fastify, Hono, Next.js, SvelteKit, Remix
- 🧩 Plugin System — Extend with custom hooks and events
- 📱 Device Tracking — Track sessions across devices
- 🚦 Rate Limiting — Built-in protection against brute force
📦 Installation
npm install @flexireact/flexiguardpnpm add @flexireact/flexiguardyarn add @flexireact/flexiguard🚀 Quick Start
1. Setup with Prisma
// lib/auth.ts
import { createAuth } from '@flexireact/flexiguard';
import { PrismaAdapter } from '@flexireact/flexiguard/adapters/prisma';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export const auth = createAuth({
adapter: PrismaAdapter(prisma),
secret: process.env.AUTH_SECRET!,
session: {
strategy: 'database', // or 'jwt'
maxAge: 30 * 24 * 60 * 60, // 30 days
},
password: {
minLength: 8,
requireUppercase: true,
requireNumbers: true,
},
});2. Create Database Schema
// schema.prisma
model User {
id String @id @default(cuid())
email String @unique
emailVerified Boolean @default(false)
passwordHash String?
name String?
image String?
role String @default("user")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sessions Session[]
accounts Account[]
}
model Session {
id String @id @default(cuid())
userId String
token String @unique
refreshToken String?
expiresAt DateTime
userAgent String?
ipAddress String?
deviceId String?
createdAt DateTime @default(now())
lastActiveAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Account {
id String @id @default(cuid())
userId String
provider String
providerAccountId String
accessToken String?
refreshToken String?
expiresAt DateTime?
tokenType String?
scope String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model VerificationToken {
id String @id @default(cuid())
identifier String
token String
type String
expiresAt DateTime
createdAt DateTime @default(now())
@@unique([identifier, token])
}3. Use in Express
// server.ts
import express from 'express';
import { createExpressAuth } from '@flexireact/flexiguard/express';
import { auth } from './lib/auth';
const app = express();
app.use(express.json());
const expressAuth = createExpressAuth(auth.getConfig());
// Apply session middleware
app.use(expressAuth.session());
// Auth routes
app.post('/auth/register', expressAuth.handleRegister);
app.post('/auth/login', expressAuth.handleLogin);
app.post('/auth/logout', expressAuth.handleLogout);
app.get('/auth/me', expressAuth.handleMe);
app.post('/auth/change-password', expressAuth.handleChangePassword);
// Protected routes
app.get('/dashboard', expressAuth.requireUser(), (req, res) => {
res.json({ user: req.user });
});
app.get('/admin', expressAuth.requireRole('admin'), (req, res) => {
res.json({ message: 'Admin area' });
});
app.listen(3000);4. Use in Next.js
// app/api/auth/[...flexiguard]/route.ts
import { createNextAuth } from '@flexireact/flexiguard/next';
import { auth } from '@/lib/auth';
const nextAuth = createNextAuth(auth.getConfig());
export const GET = nextAuth.handlers.GET;
export const POST = nextAuth.handlers.POST;// app/dashboard/page.tsx
import { createNextAuth } from '@flexireact/flexiguard/next';
import { auth } from '@/lib/auth';
import { cookies } from 'next/headers';
export default async function DashboardPage() {
const nextAuth = createNextAuth(auth.getConfig());
const session = await nextAuth.getSessionFromCookies(cookies());
if (!session) {
redirect('/login');
}
return <div>Welcome, {session.user.name}!</div>;
}🔌 Adapters
Prisma
import { PrismaAdapter } from '@flexireact/flexiguard/adapters/prisma';
import { PrismaClient } from '@prisma/client';
const adapter = PrismaAdapter(new PrismaClient());Drizzle
import { DrizzleAdapter } from '@flexireact/flexiguard/adapters/drizzle';
import { db } from './db';
import * as schema from './schema';
const adapter = DrizzleAdapter({ db, schema });Custom Adapter
import type { FlexiGuardAdapter } from '@flexireact/flexiguard';
const customAdapter: FlexiGuardAdapter = {
async createUser(data) { /* ... */ },
async getUserById(id) { /* ... */ },
async getUserByEmail(email) { /* ... */ },
// ... implement all methods
};🔐 API Reference
Core Methods
// Register a new user
const result = await auth.register(email, password, {
name: 'John Doe',
role: 'user',
});
// Login
const result = await auth.login(email, password, {
requireEmailVerified: true,
});
// Logout
await auth.logout(session);
// Validate session
const result = await auth.validateRequest(request);
// Change password
await auth.changePassword(userId, currentPassword, newPassword);
// Request password reset
await auth.requestPasswordReset(email);
// Reset password with token
await auth.resetPassword(email, token, newPassword);
// Verify email
await auth.verifyEmail(email, token);Session Management
const sessionManager = auth.getSessionManager();
// Create session
const { session, cookies } = await sessionManager.createSession(user, {
userAgent: 'Mozilla/5.0...',
ipAddress: '192.168.1.1',
});
// Validate session
const session = await sessionManager.validateSession(cookies);
// Refresh session
const { session, cookies } = await sessionManager.refreshSession(oldSession);
// Destroy session
const cookies = await sessionManager.destroySession(session);
// Get all user sessions
const sessions = await sessionManager.getUserSessions(userId);🧩 Plugins
import { createAuth, FlexiGuardPlugin } from '@flexireact/flexiguard';
const loggingPlugin: FlexiGuardPlugin = {
name: 'logging',
async afterRegister(user) {
console.log(`New user registered: ${user.email}`);
},
async afterLogin(user, session) {
console.log(`User logged in: ${user.email}`);
},
async onPasswordChanged(user) {
// Send notification email
},
};
const auth = createAuth({
adapter,
secret: process.env.AUTH_SECRET!,
plugins: [loggingPlugin],
});Available Hooks
| Hook | Description |
|------|-------------|
| beforeRegister | Modify user data before registration |
| afterRegister | Called after successful registration |
| beforeLogin | Called before login attempt |
| afterLogin | Called after successful login |
| beforeLogout | Called before logout |
| afterLogout | Called after logout |
| beforeSession | Modify session before validation |
| validateRequest | Custom request validation |
| onEmailVerified | Called when email is verified |
| onPasswordChanged | Called when password is changed |
| onPasswordReset | Called when password is reset |
| onAccountLinked | Called when OAuth account is linked |
🛡️ Security Features
Password Hashing
import { hashPassword, verifyPassword } from '@flexireact/flexiguard';
// Hash with Argon2id (default)
const hash = await hashPassword('mypassword');
// Verify
const isValid = await verifyPassword('mypassword', hash);HMAC Signing
import { signHmac, verifyHmac, signCookie, verifyCookie } from '@flexireact/flexiguard';
// Sign data
const signature = signHmac('data', secret);
// Verify
const isValid = verifyHmac('data', signature, secret);
// Signed cookies
const signedValue = signCookie('value', secret);
const value = verifyCookie(signedValue, secret);JWT
import { encodeJWT, decodeJWT } from '@flexireact/flexiguard';
// Encode
const token = await encodeJWT(
{ sub: userId, email, role },
{ secret, maxAge: 3600 }
);
// Decode & verify
const payload = await decodeJWT(token, { secret });🆚 Comparison
| Feature | FlexiGuard | Auth.js | Lucia | Clerk | |---------|:----------:|:-------:|:-----:|:-----:| | Self-hosted | ✅ | ✅ | ✅ | ❌ | | ORM-agnostic | ✅ | ⚠️ | ✅ | N/A | | Database sessions | ✅ | ✅ | ✅ | N/A | | JWT sessions | ✅ | ✅ | ❌ | N/A | | OAuth providers | ✅ | ✅ | ✅ | ✅ | | Plugin system | ✅ | ⚠️ | ❌ | ❌ | | Device tracking | ✅ | ❌ | ✅ | ✅ | | Rate limiting | ✅ | ❌ | ❌ | ✅ | | TypeScript | ✅ | ✅ | ✅ | ✅ | | Bundle size | ~15kb | ~50kb | ~10kb | N/A |
🏗️ Architecture
┌─────────────────────────────────────────────────────────────┐
│ FlexiGuard Core │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Auth │ │ Session │ │ Token Manager │ │
│ │ Manager │ │ Manager │ │ (JWT/HMAC) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Plugin System │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │
│ │ Logging │ │ Rate │ │ Email │ │ Custom Plugins │ │
│ │ │ │ Limiter │ │ Sender │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Adapter Layer │
│ ┌────────┐ ┌────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ │
│ │ Prisma │ │Drizzle │ │Sequelize │ │Mongoose│ │ Custom │ │
│ └────────┘ └────────┘ └──────────┘ └────────┘ └────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Framework Bindings │
│ ┌─────────┐ ┌─────────┐ ┌──────┐ ┌────────┐ ┌──────────┐ │
│ │ Express │ │ Fastify │ │ Hono │ │Next.js │ │SvelteKit │ │
│ └─────────┘ └─────────┘ └──────┘ └────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘📋 Configuration
interface FlexiGuardConfig {
// Required
adapter: FlexiGuardAdapter;
secret: string;
// Session
session?: {
strategy?: 'database' | 'jwt';
maxAge?: number; // seconds
updateAge?: number; // sliding window
};
// Cookies
cookies?: {
sessionToken?: {
name?: string;
options?: CookieOptions;
};
};
// JWT (if using JWT strategy)
jwt?: {
maxAge?: number;
};
// Password requirements
password?: {
minLength?: number;
requireUppercase?: boolean;
requireLowercase?: boolean;
requireNumbers?: boolean;
requireSpecialChars?: boolean;
hashAlgorithm?: 'argon2' | 'bcrypt';
};
// OAuth providers
providers?: OAuthProvider[];
// Plugins
plugins?: FlexiGuardPlugin[];
// Rate limiting
rateLimit?: {
enabled?: boolean;
maxAttempts?: number;
windowMs?: number;
};
// Callbacks
callbacks?: {
signIn?: (user, account?) => Promise<boolean>;
session?: (session) => Promise<session>;
};
// Pages (for redirects)
pages?: {
signIn?: string;
signOut?: string;
error?: string;
};
// Debug mode
debug?: boolean;
}📄 License
MIT © FlexiReact Team
