dauth-node
v6.1.0
Published
Express middleware for JWT verification and session management against the Dauth authentication service
Maintainers
Readme
dauth-md-node
Express middleware and router for JWT-based authentication against the dauth service. Two exports: dauth() middleware that verifies JWTs (via Authorization header or encrypted session cookies) and attaches req.user, and dauthRouter() that provides pre-built session-based auth routes with encrypted cookies, CSRF protection, and automatic token refresh.
Installation
npm install dauth-md-node
# or
pnpm add dauth-md-nodeFor session cookie mode or the router, also install cookie-parser:
pnpm add cookie-parserTech Stack
| Technology | Version | Purpose | |---|---|---| | Node.js | >= 18 | Runtime (native fetch required) | | TypeScript | 5.9 | Type safety | | jsonwebtoken | 9 | JWT verification (runtime dependency) | | Express | 4.18+ / 5 | Peer dependency | | cookie-parser | 1.4+ | Optional peer dependency (session/router mode) | | tsup | 8 | Build tool (CJS + ESM bundles, two entry points) | | vitest | 4 | Testing framework | | size-limit | 12 | Bundle size budget (10KB per entry) |
Usage
Middleware (Authorization header mode)
import express from 'express';
import { dauth, IRequestDauth } from 'dauth-md-node';
const app = express();
const dauthMiddleware = dauth({
domainName: 'your-domain-name',
tsk: 'your-tenant-secret-key',
});
app.get('/api/protected', dauthMiddleware, (req, res) => {
res.json({ user: (req as IRequestDauth).user });
});Middleware (session cookie mode)
import express from 'express';
import cookieParser from 'cookie-parser';
import { dauth } from 'dauth-md-node';
const app = express();
app.use(cookieParser());
const dauthMiddleware = dauth({
domainName: 'your-domain-name',
tsk: 'your-tenant-secret-key',
session: {},
});
app.get('/api/protected', dauthMiddleware, (req, res) => {
res.json({ user: req.user });
});Router (session-based auth routes)
import express from 'express';
import cookieParser from 'cookie-parser';
import { dauthRouter } from 'dauth-md-node/router';
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use('/api/auth', dauthRouter({
domainName: 'your-domain-name',
tsk: 'your-tenant-secret-key',
}));
// Available routes:
// POST /api/auth/exchange-code
// GET /api/auth/session
// POST /api/auth/logout (CSRF required)
// PATCH /api/auth/user (CSRF required)
// DELETE /api/auth/user (CSRF required)
// GET /api/auth/profile-redirect (CSRF required)API Reference
dauth(options: DauthOptions)
Returns an Express middleware.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| domainName | string | yes | - | Tenant identifier (used in API path) |
| tsk | string | yes | - | Tenant Secret Key for JWT verification |
| cache | { ttlMs: number } | no | - | Enable in-memory user cache with TTL |
| session | SessionOptions | no | - | Enable session cookie mode |
SessionOptions:
| Parameter | Type | Default | Description |
|---|---|---|---|
| cookieName | string | __Host-dauth-session (prod) / dauth-session (dev) | Session cookie name |
| secure | boolean | true (except NODE_ENV=development) | Cookie Secure flag |
| previousTsk | string | - | Previous TSK for zero-downtime key rotation |
| sessionSalt | string | built-in default | Custom HKDF salt (hex string) |
Without session: extracts Authorization header, verifies JWT with tsk, fetches user from dauth backend, attaches to req.user.
With session: reads encrypted session cookie, decrypts with key derived from tsk (falls back to previousTsk), extracts access token, verifies JWT, fetches user, attaches to req.user.
dauthRouter(options: DauthRouterOptions)
Returns an Express Router. Requires cookie-parser middleware. Import from dauth-md-node/router.
| Parameter | Type | Default | Description |
|---|---|---|---|
| domainName | string | (required) | Tenant identifier |
| tsk | string | (required) | Tenant Secret Key |
| dauthUrl | string | auto-detected | Override dauth backend URL |
| cookieName | string | __Host-dauth-session / dauth-session | Session cookie name |
| csrfCookieName | string | __Host-csrf / csrf-token | CSRF cookie name |
| maxAge | number | 2592000 (30 days) | Cookie max age in seconds |
| secure | boolean | true (except dev) | Cookie Secure flag |
| previousTsk | string | - | Previous TSK for key rotation |
| sessionSalt | string | built-in default | Custom HKDF salt (hex string) |
Router routes:
| Method | Path | CSRF | Description |
|---|---|---|---|
| POST | /exchange-code | No | Exchange auth code for session, set cookies, return { user, domain, isNewUser } |
| GET | /session | No | Check session, auto-refresh if token expires within 5min, return { user, domain } |
| POST | /logout | Yes | Revoke refresh token (fire-and-forget), clear cookies |
| PATCH | /user | Yes | Proxy user update to dauth backend with auto-refresh |
| DELETE | /user | Yes | Delete user account, clear cookies |
| GET | /profile-redirect | Yes | Generate profile code, return { redirectUrl } |
CSRF uses the double-submit cookie pattern: POST /exchange-code sets a CSRF cookie (httpOnly: false), and subsequent state-changing requests must include the cookie value as the x-csrf-token header.
Exported types (from dauth-md-node)
IDauthUser-- user object (name, email, avatar, role, language, authMethods, etc.)AuthMethodType--'magic-link' | 'passkey'IRequestDauth-- extends ExpressRequestwithuser: IDauthUserDauthOptions-- middleware factory optionsSessionOptions-- session cookie configurationUserCache-- cache class (for direct usage/testing)CacheOptions-- cache configuration type
Exported types (from dauth-md-node/router)
DauthRouterOptions-- router factory options
Environment detection
The middleware resolves the dauth backend URL in this order:
DAUTH_URLenvironment variableNODE_ENV=development->http://localhost:4012/api/v1- Default ->
https://dauth.ovh/api/v1
The router also accepts dauthUrl in options, which takes priority over the env var.
Error responses (middleware)
| Scenario | Status | Status Field |
|---|---|---|
| Missing Authorization header (header mode) | 403 | token-not-found |
| Missing session cookie (session mode) | 401 | no-session |
| Invalid/undecryptable session cookie | 401 | session-invalid |
| JWT expired | 401 | token-expired |
| Invalid JWT or bad TSK | 401 | tsk-not-invalid / token-invalid |
| User not found | 404 | user-not-found |
| Backend server error | 500 | error |
| Other backend status | 501 | request-error |
Scripts
| Script | Description |
|---|---|
| pnpm start | Watch mode (tsup --watch) |
| pnpm build | Production build (CJS + ESM + types, two entry points) |
| pnpm test | Run vitest tests (80 tests) |
| pnpm test:coverage | Coverage report (v8, 70% threshold) |
| pnpm typecheck | TypeScript type checking |
| pnpm size | Check bundle size (10KB budget per entry) |
| pnpm format | Prettier formatting |
Testing
80 tests across 7 files using vitest 4 (node environment).
pnpm test
pnpm test:coveragePublishing
Automated via GitHub Actions. Push a v* tag to trigger build, test, and npm publish.
# 1. Bump version in package.json
# 2. Commit and tag
git tag v4.0.1
git push origin main --tags
# 3. GitHub Actions publishes to npm automaticallyRequires NPM_TOKEN secret configured in the GitHub repo.
Code Style
Prettier: 80 char width, single quotes, semicolons, trailing commas (es5), 2-space indent.
License
MIT
