@janindu-pathirana/authkit
v1.0.1
Published
Reusable authentication utilities for Node.js and TypeScript applications.
Maintainers
Readme
@janindu-pathirana/authkit
Reusable authentication utilities for Node.js and TypeScript applications. Username/password credentials on PostgreSQL with bcrypt hashing, JWT sessions, and migrations.
Requirements: Node.js 18+, PostgreSQL 13+ (uses gen_random_uuid()).
Installation
npm install @janindu-pathirana/authkitRun database migrations
Set DATABASE_URL, then run:
npx authkit migrateThis applies AuthKit migrations (auth + auth_sessions tables).
Run it after installing or upgrading @janindu-pathirana/authkit.
npx authkit init remains available as a backward-compatible alias.
auth table
| Column | Type |
| --- | --- |
| id | UUID (primary key) |
| username | TEXT (unique) |
| password | TEXT |
| created_at | TIMESTAMPTZ |
| deleted_at | TIMESTAMPTZ (nullable) |
auth_sessions table
| Column | Type |
| --- | --- |
| id | UUID (primary key) |
| user_id | UUID (FK → auth) |
| refresh_token_hash | TEXT (unique) |
| expires_at | TIMESTAMPTZ |
| revoked_at | TIMESTAMPTZ (nullable) |
| created_at | TIMESTAMPTZ |
You can also put DATABASE_URL in a .env file in the current directory.
Quick start with createAuthKit
import {
createAuthKit,
consoleLogger,
createMemoryRateLimiter,
} from "@janindu-pathirana/authkit";
const auth = createAuthKit({
connectionString: process.env.DATABASE_URL,
jwtSecret: process.env.AUTHKIT_JWT_SECRET!, // required for sessions / middleware
logger: consoleLogger, // optional; logging is silent by default
rateLimiter: createMemoryRateLimiter({ maxAttempts: 5, windowMs: 15 * 60 * 1000 }),
});
await auth.connect();
await auth.migrate();
await auth.register("jane", "plain-password");
const session = await auth.loginWithSession("jane", "plain-password");
// { user, accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt, sessionId }
const refreshed = await auth.refresh(session.refreshToken);
await auth.logout(refreshed.refreshToken);
await auth.close();Express-compatible middleware
import express from "express";
const app = express();
app.get("/me", auth.requireAuth(), (req, res) => {
res.json({ user: req.user });
});createRequireAuth / authenticateRequest are also available as standalone helpers.
Programmatic usage (standalone helpers)
import {
createDb,
migrateAuthTable,
register,
login,
loginWithSession,
updatePassword,
deleteUser,
restoreUser,
} from "@janindu-pathirana/authkit";
const db = createDb({
connectionString: process.env.DATABASE_URL,
});
await db.connect();
await migrateAuthTable(db);
const user = await register(db, "jane", "plain-password");
// returns: { id, username, createdAt, deletedAt }
const loggedIn = await login(db, "jane", "plain-password");
const session = await loginWithSession(db, "jane", "plain-password", {
jwtSecret: process.env.AUTHKIT_JWT_SECRET!,
});
await updatePassword(db, "jane", "plain-password", "new-plain-password");
await deleteUser(db, "jane");
await restoreUser(db, "jane");
await db.close();Sessions
- Access token: HS256 JWT (default TTL 15 minutes)
- Refresh token: opaque random value; only a SHA-256 hash is stored
- Refresh rotates the refresh token (old one is revoked)
logout(refreshToken)revokes one session;logoutAll(userId)revokes all
Rate limiting hooks
import { createAuthKit, createMemoryRateLimiter } from "@janindu-pathirana/authkit";
const rateLimiter = createMemoryRateLimiter({ maxAttempts: 5 });
const auth = createAuthKit({
connectionString: process.env.DATABASE_URL!,
jwtSecret: process.env.AUTHKIT_JWT_SECRET!,
rateLimiter,
hooks: {
onLoginFailure: ({ username, reason }) => {
console.warn("login failed", username, reason);
},
},
});For multi-instance apps, implement hooks.checkRateLimit against Redis (or similar) instead of the in-memory helper.
Validation defaults
| Rule | Default | | --- | --- | | Username length | 1–64 characters (after trim) | | Password length (register / new password) | 8–72 characters | | Login password | non-empty, max 72 characters | | Access token TTL | 900 seconds | | Refresh token TTL | 2_592_000 seconds (30 days) |
Errors
Auth failures throw AuthKitError with a code such as INVALID_CREDENTIALS, USERNAME_TAKEN, TOKEN_EXPIRED, SESSION_REVOKED, or RATE_LIMITED.
import { AuthKitError, isAuthKitError } from "@janindu-pathirana/authkit";
try {
await auth.register("jane", "short");
} catch (error) {
if (isAuthKitError(error)) {
console.error(error.code, error.message);
}
}Development
npm install
npm run build
npm run typecheck
npm testLicense
MIT
