A drop-in but safer alternative to jsonwebtoken
with modern security practices, TypeScript support, and enterprise features.
The popular jsonwebtoken
library has several security and developer experience issues:
Issue | jsonwebtoken |
@plus99/secure-jwt |
---|---|---|
Insecure algorithm support | ❌ Supports insecure none algorithm |
✅ Blocks none completely |
Token expiration | ❌ No default expiration | ✅ Mandatory expiration (1h default) |
TypeScript support | ❌ Weak TypeScript support | ✅ Full TypeScript native |
Error handling | ❌ Generic error handling | ✅ Typed error classes |
Crypto operations | ❌ Blocking crypto operations | ✅ Async/non-blocking |
JWKS support | ❌ No JWKS support | ✅ Built-in JWKS with caching |
Enterprise integrations | ❌ No enterprise integrations | ✅ Auth0, Cognito, Okta support |
CLI tooling | ❌ No CLI tooling | ✅ DevOps-ready CLI |
npm install @plus99/secure-jwt
import { signJWT } from '@plus99/secure-jwt';
const token = await signJWT(
{ sub: 'user123', role: 'admin' },
{
secret: process.env.JWT_SECRET!,
alg: 'HS256',
expiresIn: '1h' // Mandatory - no indefinite tokens!
}
);
import { verifyJWT, TokenExpiredError } from '@plus99/secure-jwt';
try {
const payload = await verifyJWT(token, {
secret: process.env.JWT_SECRET!,
alg: 'HS256'
});
console.log('Valid token:', payload);
} catch (error) {
if (error instanceof TokenExpiredError) {
console.log('Token expired');
}
}
import { verifyJWT } from '@plus99/secure-jwt';
// Auth0
const payload = await verifyJWT(token, {
jwksUri: 'https://your-domain.auth0.com/.well-known/jwks.json',
issuer: 'https://your-domain.auth0.com/',
audience: 'your-api-identifier'
});
// AWS Cognito
const payload = await verifyJWT(token, {
jwksUri: 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123/.well-known/jwks.json'
});
Signs a JWT with secure defaults.
interface SignOptions {
secret: string | Buffer;
alg: SecureAlgorithm;
expiresIn?: string | number; // Default: '1h'
notBefore?: string | number;
audience?: string;
issuer?: string;
subject?: string;
}
const token = await signJWT(payload, options);
Verifies a JWT with strict validation.
interface VerifyOptions {
secret?: string | Buffer;
alg?: SecureAlgorithm;
jwksUri?: string; // For enterprise providers
audience?: string;
issuer?: string;
clockTolerance?: number;
}
const payload = await verifyJWT(token, options);
Decodes JWT without verification (for debugging).
const { header, payload } = decodeJWT(token);
All errors are typed for better error handling:
import {
TokenExpiredError,
InvalidSignatureError,
InvalidTokenError
} from '@plus99/secure-jwt';
try {
await verifyJWT(token, options);
} catch (error) {
if (error instanceof TokenExpiredError) {
// Handle expired token
} else if (error instanceof InvalidSignatureError) {
// Handle invalid signature
}
}
- Auth0 -
verifyEnterpriseJWT(token, 'auth0', { domain: 'your-domain.auth0.com' })
- AWS Cognito -
verifyEnterpriseJWT(token, 'cognito', { region: 'us-east-1', userPoolId: 'us-east-1_ABC123' })
- Okta -
verifyEnterpriseJWT(token, 'okta', { domain: 'your-domain.okta.com' })
- Firebase -
verifyEnterpriseJWT(token, 'firebase', { projectId: 'your-project' })
- Azure AD -
verifyEnterpriseJWT(token, 'azure', { tenantId: 'your-tenant-id' })
- Generic OIDC -
verifyEnterpriseJWT(token, 'oidc', { issuer: 'https://your-provider.com' })
import { verifyEnterpriseJWT } from '@plus99/secure-jwt';
const payload = await verifyEnterpriseJWT(
token,
'auth0',
{ domain: 'your-domain.auth0.com', audience: 'your-api' }
);
import { generateSecurityAssessment } from '@plus99/secure-jwt';
const decoded = decodeJWT(token);
const assessment = generateSecurityAssessment(
decoded.payload,
decoded.header.alg
);
console.log(`Security Score: ${assessment.score}/100`);
console.log('Violations:', assessment.violations);
console.log('Recommendations:', assessment.recommendations);
import { recommendAlgorithm } from '@plus99/secure-jwt';
const rec = recommendAlgorithm('enterprise');
console.log(`Recommended: ${rec.algorithm} - ${rec.reasoning}`);
The library includes a comprehensive CLI for DevOps workflows:
# Basic signing
npx secure-jwt sign '{"sub":"user123","role":"admin"}' --secret mysecret
# Advanced options
npx secure-jwt sign payload.json \
--secret $JWT_SECRET \
--alg HS256 \
--expires 2h \
--issuer https://auth.company.com \
--audience https://api.company.com
# Verify with secret
npx secure-jwt verify $TOKEN --secret mysecret
# Verify with JWKS (Enterprise)
npx secure-jwt verify $TOKEN \
--jwks-uri https://your-domain.auth0.com/.well-known/jwks.json
# Strict validation
npx secure-jwt verify $TOKEN \
--secret mysecret \
--issuer https://auth.company.com \
--audience https://api.company.com
# Decode without verification
npx secure-jwt decode $TOKEN
# Generate sample payloads
npx secure-jwt generate --type user
npx secure-jwt generate --type api
# Auth0
npx secure-jwt verify $TOKEN \
--jwks-uri https://YOUR_DOMAIN.auth0.com/.well-known/jwks.json
# AWS Cognito
npx secure-jwt verify $TOKEN \
--jwks-uri https://cognito-idp.REGION.amazonaws.com/USER_POOL_ID/.well-known/jwks.json
# Show all CLI examples
npx secure-jwt examples
Start the interactive web playground to test all features:
npm run dev
Visit http://localhost:5000
to access the playground with:
- JWT signing and verification forms
- Enterprise provider testing
- Security analysis tools
- Real-time examples
Run the comprehensive test suite:
npm test
npm run test:watch
Run example scripts to see the library in action:
npm run examples:sign
npm run examples:verify
npm run examples:jwks
npm run build
import { DEFAULT_SECURITY_POLICY, DEVELOPMENT_SECURITY_POLICY } from '@plus99/secure-jwt';
// Use development policy for relaxed validation
const assessment = generateSecurityAssessment(
payload,
algorithm,
DEVELOPMENT_SECURITY_POLICY
);
import { clearJWKSCache, getJWKSCacheStats } from '@plus99/secure-jwt';
// Clear cache
clearJWKSCache();
// Get cache statistics
const stats = getJWKSCacheStats();
console.log(`Cache size: ${stats.size}, URLs: ${stats.entries}`);
- Developers → Safer defaults, async performance, typed APIs
- Security Teams → Eliminates common JWT misconfigurations
- Enterprise Apps → Easy integration with Auth0, AWS Cognito, Okta, etc.
- DevOps → CLI tooling for scripting and debugging
Replace your existing JWT operations:
// Before (jsonwebtoken)
import jwt from 'jsonwebtoken';
const token = jwt.sign(payload, secret); // ⚠️ No expiration!
const decoded = jwt.verify(token, secret); // ⚠️ Generic errors
// After (@plus99/secure-jwt)
import { signJWT, verifyJWT } from '@plus99/secure-jwt';
const token = await signJWT(payload, { secret, alg: 'HS256' }); // ✅ Secure defaults
const decoded = await verifyJWT(token, { secret, alg: 'HS256' }); // ✅ Typed errors
MIT License - see LICENSE file for details.
Contributions are welcome! Please read our contributing guidelines and submit pull requests.
- 🐛 Issues
@plus99/secure-jwt - Because security should be the default, not an afterthought.