authrix
Version:
Lightweight, flexible authentication library for Node.js and TypeScript.
410 lines (304 loc) • 15 kB
Markdown
# Authrix
<div align="center">
<img src="./logo/logo.svg" alt="Authrix Logo" width="220" height="180" />
<h3>Unified, framework‑agnostic authentication for Node.js, TypeScript & modern runtimes</h3>
</div>
[](https://www.npmjs.com/package/authrix)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
[](https://jestjs.io/)
[](#security)
Authrix provides production‑grade authentication primitives with minimal ceremony: JWT sessions, secure cookie handling, rolling session refresh, password flows, SSO/OAuth, email flows, and extensible adapters. Version 2.1 introduces the **unified `auth` namespace** simplifying the API surface while remaining backward compatible (legacy exports emit one‑time deprecation warnings).
## TL;DR
```ts
import { initAuth, auth } from 'authrix';
import { mongoAdapter } from 'authrix/adapters/mongo';
initAuth({
jwtSecret: process.env.JWT_SECRET!,
db: mongoAdapter,
cookieName: 'auth_token',
sessionMaxAgeMs: 7 * 24 * 60 * 60 * 1000,
rollingSessionEnabled: true,
rollingSessionThresholdSeconds: 15 * 60, // refresh when ≤ 15m left
});
// Express example
app.post('/api/auth/signup', async (req, res) => {
const { email, password } = req.body;
const { user } = await auth.actions.signup(email, password, { res }); // sets cookie
res.status(201).json({ success: true, user });
});
app.post('/api/auth/signin', async (req, res) => {
const { email, password } = req.body;
const { user } = await auth.actions.signin(email, password, { res });
res.json({ success: true, user });
});
app.get('/api/auth/me', async (req, res) => {
const user = await auth.session.getCurrentUserFromRequest(req); // auto token extract
if (!user) return res.status(401).json({ success: false, error: 'Not authenticated' });
res.json({ success: true, user });
});
app.get('/api/private', auth.middleware.requireAuth, (req, res) => {
res.json({ success: true, user: (req as any).user });
});
```
## Table of Contents
1. [Architecture](#architecture)
2. [Feature Overview](#features)
3. [Installation](#installation)
4. [Initialization & Configuration](#configuration)
5. [Unified API Surface](#unified-api)
6. [Framework Usage](#framework-usage)
7. [Sessions & Rolling Refresh](#sessions-and-rolling-refresh)
8. [Cookies & Security Defaults](#cookies)
9. [OAuth / SSO](#oauth--sso)
10. [Database Adapters](#database-adapters)
11. [Email & 2FA / Forgot Password](#email--2fa--recovery)
12. [Structured Logging](#logging)
13. [Extensibility (Adapters & Providers)](#extensibility)
14. [Migration (≤2.0 → 2.1)](#migration)
15. [Roadmap](#roadmap)
16. [Contributing](#contributing)
17. [License](#license)
## Architecture
```
┌──────────────────────────────────────────────┐
│ auth │ <- unified facade
├──────────────┬───────────────┬───────────────┤
│ actions │ session │ middleware │
│ signup/signin│ token→user │ require/opt │
├──────────────┴───────┬───────┴──────┬────────┤
│ handlers (Next.js) │ cookies util │ env │
├───────────────────────────────────────────────┤
│ Core Logic (pure functions) │
├───────────────────────────────────────────────┤
│ Adapters: Mongo | PostgreSQL | (Prisma WIP) │
│ Providers: Google | GitHub | ... │
│ Email: Gmail | SendGrid | Resend | SMTP │
└───────────────────────────────────────────────┘
```
Design principles:
* Pure core (no framework imports) → thin framework façades.
* Minimal public surface; strong defaults; explicit opt‑ins.
* Extensible via small interfaces (db adapter, email provider, oauth provider).
* Predictable error model (`Error` with message; route layer decides JSON shape).
## Features
| Area | Highlights |
|------|------------|
| Auth Core | Signup, Signin, Logout, Session inspection |
| Security | Explicit JWT signature validation; cookie normalization; optional rolling refresh |
| Cookies | Central name + normalization (HttpOnly, SameSite=lax, Secure in prod) |
| OAuth/SSO | pluggable providers (Google, GitHub) with state verification |
| Email | Multiple transports (gmail, sendgrid, resend, smtp, console) |
| Recovery | Forgot password + (email) 2FA foundations |
| Adapters | MongoDB, PostgreSQL, Prisma (scaffold) |
| Logging | Structured logger with contextual warnings |
| Extensibility | Simple contracts for adapters/providers/email |
## Installation
```bash
npm install authrix
# or yarn add authrix / pnpm add authrix / bun add authrix
```
Peer deps (install only what you use): `mongodb`, `pg`, `next`, `react`, etc.
## Configuration
Call `initAuth` once at application bootstrap (server entry, Next.js edge route, etc.).
```ts
import { initAuth } from 'authrix';
import { mongoAdapter } from 'authrix/adapters/mongo';
initAuth({
jwtSecret: process.env.JWT_SECRET!, // required, min 32 chars recommended
db: mongoAdapter, // optional if only stateless operations
cookieName: 'auth_token', // optional override
forceSecureCookies: false, // force Secure attr regardless of NODE_ENV
sessionMaxAgeMs: 7 * 24 * 60 * 60 * 1000,// absolute lifetime of issued tokens
rollingSessionEnabled: true, // enable rolling refresh
rollingSessionThresholdSeconds: 15 * 60, // refresh when remaining life ≤ threshold
});
```
Config fields (selected):
* `jwtSecret` (string, required)
* `db` (adapter) – provides persistence for user lookup & future session state needs
* `cookieName` (string) – default: `auth_token`
* `sessionMaxAgeMs` (number) – default: 7 days
* `rollingSessionEnabled` (boolean) – off by default if unspecified
* `rollingSessionThresholdSeconds` (number) – default internal heuristic (e.g. 900)
* `forceSecureCookies` (boolean) – override environment heuristic
Access at runtime via `auth.config` (read-only snapshot / accessor pattern) if needed.
## Environment Requirements
- JWT_SECRET (required)
- A strong secret used to sign JWTs. Recommended length: 32+ characters.
- Required in all environments. Authrix will throw if missing when creating tokens.
- AUTHRIX_PASSWORD_PEPPER (required in production)
- Additional secret applied during password hashing to harden stored hashes.
- Production: must be set explicitly. The library throws on startup if missing.
- Development: if not set, Authrix derives a stable pepper from `jwtSecret` when available; if `jwtSecret` is not yet initialized, a temporary pepper is generated and later upgraded once `jwtSecret` is set. Always configure a real pepper before deploying.
Notes
- Keep both secrets in a secure secret store (not in source control).
- Rotating `jwtSecret` invalidates existing sessions. Plan for a rotation strategy if needed.
## Unified API
```ts
import { auth } from 'authrix';
auth.actions.signup(email, password, { res?, autoSignin? });
auth.actions.signin(email, password, { res? });
auth.actions.logout({ res? });
const user = await auth.session.getCurrentUserFromToken(token);
const user2 = await auth.session.getCurrentUserFromRequest(req);
const { user: refreshed, refreshedToken } = await auth.session.getCurrentUserFromTokenWithRefresh(token);
// Express / API middleware
auth.middleware.requireAuth(req, res, next); // attaches user → req.user
auth.middleware.optionalAuth(req, res, next);
// Next.js route handlers (App Router) dynamic helpers
auth.handlers.signup(request);
auth.handlers.signin(request);
auth.handlers.logout(request);
auth.handlers.currentUser(request);
// Cookie helpers
auth.cookies.name; // string
auth.cookies.create(token, opts?); // returns Set-Cookie string
auth.cookies.clear(); // logout cookie string
// Environment insight
auth.env.isNext; auth.env.isNode; auth.env.details;
```
All legacy direct exports (e.g. `signupCore`) still work but emit a single deprecation warning (development only).
## Framework Usage
### Express
```ts
app.post('/api/auth/signup', async (req, res) => {
const { email, password } = req.body;
const { user } = await auth.actions.signup(email, password, { res });
res.status(201).json({ success: true, user });
});
app.get('/api/secure', auth.middleware.requireAuth, (req, res) => {
res.json({ success: true, user: (req as any).user });
});
```
### Next.js (App Router)
```ts
// app/api/auth/signin/route.ts
import { auth } from 'authrix';
export const POST = auth.handlers.signin; // returns Response with cookie
// app/api/auth/me/route.ts
import { auth } from 'authrix';
export const GET = auth.handlers.currentUser;
```
### Universal (Raw Fetch / Edge)
Use `auth.session.getCurrentUserFromToken(token)` after extracting cookie manually if necessary.
## Sessions and Rolling Refresh
Rolling refresh keeps users active without silent expiration while preserving an absolute max lifetime:
1. Each request (middleware or explicit call) checks remaining lifetime.
2. If `remainingSeconds ≤ rollingSessionThresholdSeconds` and `rollingSessionEnabled`, a new token is issued + cookie updated.
3. Token is still fully signed & time‑boxed by `sessionMaxAgeMs` at issue time.
Disable by setting `rollingSessionEnabled: false`.
Edge cases handled: tampered token → rejection; expired token → null user; refresh only when threshold reached (no churn).
## Cookies
Defaults (unless overridden):
* `HttpOnly: true`
* `SameSite: lax`
* `Secure: true` in production OR when `forceSecureCookies` true
* `Path: /`
* `Max-Age` normalized to seconds (internal uses ms; outward always correct)
Helpers:
```ts
const headerValue = auth.cookies.create(token, { sameSite: 'strict' });
res.setHeader('Set-Cookie', headerValue);
```
Logout cookie:
```ts
res.setHeader('Set-Cookie', auth.cookies.clear());
```
## OAuth / SSO
Providers (Google, GitHub) reside under `providers/*`. High‑level orchestration lives in core and is exposed via handler helpers (see `docs/OAUTH_USAGE.md`). Unified namespace does not yet encapsulate bespoke OAuth flows; migration planned (see roadmap). For now, continue using documented provider helpers; future minor will add `auth.oauth.*` façade.
## Database Adapters
Currently shipped: MongoDB, PostgreSQL. Prisma scaffold exists (contributions welcome).
Adapter contract snapshot (simplified):
```ts
interface AuthDbAdapter {
createUser(data): Promise<User>;
getUserByEmail(email): Promise<User|null>;
getUserById(id): Promise<User|null>;
updateUser(id, partial): Promise<User>;
// plus SSO + password reset helpers
}
```
Normalization: emails / usernames are lowercased & trimmed in adapters (maintain this in custom adapters). Duplicate conflicts must throw informative `Error` messages.
## Email & 2FA / Recovery
Email providers selected at config time. See `docs/2FA_EMAIL_SETUP_GUIDE.md` & `docs/SSO_FORGOT_PASSWORD_GUIDE.md` for end‑to‑end flows. These modules will adopt structured logging fully in upcoming releases (currently partially migrated).
## Logging
Use the central logger:
```ts
import { logger } from 'authrix';
logger.debug('Auth flow start', { email });
logger.structuredWarn({
category: 'deprecation',
action: 'legacy-signup',
outcome: 'fallback',
message: 'signupCore is deprecated; use auth.actions.signup'
});
```
Categories used so far: `deprecation`, `security`, `adapter`, `session`.
You can wrap or replace output by providing a custom transport (see source of `utils/logger.ts`).
## Extensibility
| Extension | How |
|-----------|-----|
| DB Adapter | Implement `AuthDbAdapter` and pass to `initAuth` |
| Email Provider | Implement send interface (see existing providers) |
| OAuth Provider | Follow provider module pattern (token exchange + profile map) |
| Middleware | Compose `auth.middleware.requireAuth` inside your framework adapters |
Design goals: small, testable, dependency‑light surfaces.
## Migration
If upgrading from ≤2.0.x:
| Old | New |
|-----|-----|
| `signupCore(email,pw,res?)` | `auth.actions.signup(email,pw,{res})` |
| `signinCore` | `auth.actions.signin` |
| `logoutCore` | `auth.actions.logout` |
| `getCurrentUser(req)` | `auth.session.getCurrentUserFromRequest(req)` |
| scattered cookie helpers | `auth.cookies.*` |
Deprecations emit once per symbol (non‑prod). Planned removal: 3.0.0 (see roadmap). Begin migrating now; wrappers will persist through at least 2.3.x.
## Roadmap
See also `RELEASE_NOTES_2.1.0.md` for detailed schedule.
### Near‑Term (2.1.x → 2.2.x)
* Complete structured logging coverage (providers, email).
* Rolling session test matrix & docs.
* Expanded cookie matrix across runtimes.
* Publish detailed migration guide (FAQ, code mods suggestions).
### Mid‑Term (2.2.x → 2.3.x)
* Provider observability events (oauth.start/success/failure).
* Finalize Prisma adapter.
* JWT secret rotation helper.
* Enhanced recovery & 2FA audit logging.
### 3.0.0 Themes
* Remove deprecated exports.
* Optional strict security mode (always secure cookies, enforced config validation).
* Stable machine‑readable error codes + typed error classes.
* Audit event publishing hook.
## Contributing
1. Fork & clone.
2. `npm install`
3. Run tests: `npm test`
4. For significant changes open a draft PR early.
Quality gates: build (`npm run build`), type checks, Jest. Avoid committing `dist/`.
Issue labels you can use: `adapter`, `provider`, `security`, `docs`, `enhancement`.
## License
MIT © 2025 Authrix Contributors
Need help or migration guidance? Open an issue with the `unified-api` label.