A flexible JWT authentication library for Node.js with support for Express, Fastify, NestJS, and pure Node.js applications.
Note: This package is in pre-1.0 development. The API may change before the 1.0.0 release.
- đź”’ Secure JWT token generation and verification
- 🔄 Support for multiple frameworks:
- Express middleware
- Fastify plugin
- NestJS guard
- Pure Node.js request verifier
- 🎯 TypeScript support with generic payload types
- 🔌 Customizable token extractors
- ⚡ ESM and CommonJS support
- đź§Ş Comprehensive test coverage
# Using npm
npm install jwt-flex
# Using yarn
yarn add jwt-flex
# Using pnpm
pnpm add jwt-flex
# Using bun
bun add jwt-flexThe library is highly optimized for size with code splitting and separate bundles for each framework:
Framework-specific entry points (additional functionality loaded on demand):
- Core functionality: 0.33 KB
- Express middleware: 0.42 KB
- Fastify plugin: 2.20 KB
- NestJS guard: 0.80 KB
- Node.js utilities: 0.74 KB
Shared core bundles (loaded once and shared):
- Core utilities: 59.80 KB
- Shared helpers: 0.11 KB
Each framework integration is available as a separate import to keep bundle sizes minimal:
// Core JWT functionality
import { signToken, verifyToken } from 'jwt-flex';
// Framework-specific imports
import { expressMiddleware } from 'jwt-flex/express';
import { fastifyPlugin } from 'jwt-flex/fastify';
import { JwtAuthGuard, UseJwtAuth } from 'jwt-flex/nest';
import { verifyRequest } from 'jwt-flex/node';import { signToken, verifyToken } from 'jwt-flex';
// Sign a token
const payload = { userId: 1, role: 'admin' };
const token = await signToken(payload, {
secret: 'your-secret',
expiresIn: '1h',
algorithm: 'HS256', // optional, defaults to HS256
});
// Verify a token
const decoded = await verifyToken(token, {
secret: 'your-secret',
algorithms: ['HS256'], // optional
});import { expressMiddleware } from 'jwt-flex/express';
app.use(
expressMiddleware({
secret: 'your-secret',
credentialsRequired: true, // optional, defaults to true
}),
);
// Access the decoded payload in your route handlers
app.get('/protected', (req, res) => {
console.log(req.user); // decoded token payload
res.json({ message: 'Protected route' });
});import { fastifyPlugin } from 'jwt-flex/fastify';
await app.register(fastifyPlugin, {
secret: 'your-secret',
credentialsRequired: true, // optional, defaults to true
});
// Access the decoded payload in your route handlers
app.get('/protected', async (request, reply) => {
console.log(request.user); // decoded token payload
return { message: 'Protected route' };
});import { JwtAuthGuard, UseJwtAuth } from 'jwt-flex/nest';
// Use as a guard
@UseGuards(new JwtAuthGuard({ secret: 'your-secret' }))
export class ProtectedController {
@Get()
getProtectedResource() {
return 'Protected resource';
}
}
// Or use as a decorator
@UseJwtAuth({ secret: 'your-secret' })
export class ProtectedController {
@Get()
getProtectedResource() {
return 'Protected resource';
}
}import { verifyRequest } from 'jwt-flex/node';
import { createServer } from 'http';
const server = createServer(async (req, res) => {
const result = await verifyRequest(req, {
secret: 'your-secret',
credentialsRequired: true, // optional, defaults to true
});
if (!result.isAuthenticated) {
res.statusCode = 401;
res.end(JSON.stringify({ error: result.error }));
return;
}
// Access the decoded payload
console.log(result.payload);
res.end('Protected resource');
});The library provides several built-in token extractors and supports custom extractors:
- Bearer Token Extractor
import { fromAuthHeaderAsBearerToken } from 'jwt-flex';
app.use(
expressMiddleware({
secret: 'your-secret',
extractors: [fromAuthHeaderAsBearerToken()],
}),
);- Query Parameter Extractor
import { fromQueryParameter } from 'jwt-flex';
app.use(
expressMiddleware({
secret: 'your-secret',
extractors: [fromQueryParameter('access_token')],
}),
);- Cookie Extractor
import { fromCookie } from 'jwt-flex';
app.use(
expressMiddleware({
secret: 'your-secret',
extractors: [fromCookie('auth_token')],
}),
);You can create your own token extractors by implementing the TokenExtractor interface:
import { TokenExtractor } from 'jwt-flex';
// Create a custom token extractor
const customExtractor: TokenExtractor = (req) => {
// Extract token from custom source
return req.headers['x-custom-token'] || null;
};
// Use the custom extractor
app.use(
expressMiddleware({
secret: 'your-secret',
extractors: [customExtractor],
}),
);You can use multiple extractors with fallback:
app.use(
expressMiddleware({
secret: 'your-secret',
extractors: [
fromAuthHeaderAsBearerToken(),
fromCookie('auth_token'),
fromQueryParameter('access_token'),
customExtractor,
],
}),
);The extractors are tried in order until a token is found.
Signs a payload and returns a JWT token.
Options:
secret: string- Secret key for signingexpiresIn?: string | number- Token expiration timealgorithm?: string- Signing algorithm (default: 'HS256')
Verifies a token and returns the decoded payload.
Options:
secret: string- Secret key for verificationalgorithms?: string[]- Allowed algorithms (default: ['HS256'])
All middleware adapters (Express, Fastify, NestJS, Node.js) accept these options:
secret: string- Secret key for token verificationcredentialsRequired?: boolean- Whether to require authentication (default: true)extractors?: TokenExtractor[]- Custom token extractorsalgorithms?: string[]- Allowed algorithms (default: ['HS256'])
The library provides specific error classes for better error handling:
TokenExpiredError- Thrown when the token has expiredInvalidTokenError- Thrown when the token signature is invalidMalformedTokenError- Thrown when the token format is invalidHttpError- Used in Fastify middleware for HTTP-specific errors (includes status code)
import { verifyToken, TokenExpiredError, InvalidTokenError, MalformedTokenError } from 'jwt-flex';
try {
const decoded = await verifyToken(token, { secret: 'your-secret' });
// Token is valid, use decoded payload
} catch (error) {
if (error instanceof TokenExpiredError) {
console.error('Token has expired');
// Handle expired token
} else if (error instanceof InvalidTokenError) {
console.error('Invalid token signature');
// Handle invalid signature
} else if (error instanceof MalformedTokenError) {
console.error('Malformed token');
// Handle malformed token
} else {
console.error('Unknown error:', error);
// Handle other errors
}
}- Node.js (v18 or higher)
- Clone the repository
git clone https://github.com/majidkn/jwt-flex.git
cd jwt-flex- Install dependencies
bun installbun run build- Build everything (JS bundles + TypeScript declarations)bun run build:js- Build and optimize JS bundles onlybun run build:types- Generate TypeScript declarations onlybun run test- Run testsbun run lint- Run ESLintbun run format- Format code with Prettierbun run format:check- Check code formattingbun run clean- Clean build directory
The project uses Bun's build system with advanced optimizations:
# Clean and build everything
bun run build
# Individual build steps
bun run build:js # Build and optimize JS bundles
bun run build:types # Generate TypeScript declarationsThe build process:
- Uses code splitting to share common code
- Minifies and optimizes each bundle
- Generates separate entry points for each framework
- Creates TypeScript declaration files
- Supports both ESM and CommonJS formats
Output bundles:
- Framework entry points (0.33 KB - 2.12 KB each)
- Shared core bundle (59.71 KB, loaded once)
- TypeScript declarations for all modules
The project uses a single TypeScript configuration for both development and production builds, making it easier to maintain and extend.
Contributions are welcome! Please feel free to submit a Pull Request.
- Bun (latest version) - Used for development tasks (building, testing, linting)
- ESLint - For code linting (installed via bun)
- Prettier - For code formatting (installed via bun)
Before submitting a PR:
- Make sure all tests pass:
bun run test - Run the linter:
bun run lint - Check code formatting:
bun run format:check - Build the project:
bun run build
MIT