@zewstid/node
Official ZewstID SDK for Node.js - Authentication for backend applications.
✨ Features
Authentication & Authorization (v0.1.0)
- ✨ JWT Validation - Fast and secure token verification
- 🔐 JWKS Caching - Automatic key rotation with intelligent caching
- 🛡️ Role-Based Access Control - Built-in RBAC middleware
- 🔑 Token Introspection - Validate and introspect access tokens
- ⚡ High Performance - Optimized for production workloads
- 🎯 TypeScript - Full type safety out of the box
Framework Integration
- 📦 Express Middleware - Ready-to-use authentication middleware
- ⚡ Fastify Plugin - Native Fastify support
- 🔧 Standalone Client - Use in any Node.js environment
- 🎨 Flexible - Works with Koa, Hapi, or vanilla Node.js
Developer Experience
- ⚡ Minimal Dependencies - Uses only for JWT handling
jose - 🐛 Debug Mode - Detailed logging for troubleshooting
- 📖 Comprehensive Docs - Clear examples and API reference
- 🔄 Auto Key Rotation - JWKS keys cached with auto-refresh
🚀 Installation
From ZewstID npm Registry:
npm install @zewstid/node --registry https://npm.zewstid.com/
Or configure registry in .npmrc
# .npmrc @zewstid:registry=https://npm.zewstid.com/
Then install normally:
npm install @zewstid/node
Quick Start
Standalone Usage
import { ZewstID } from '@zewstid/node'; const zewstid = new ZewstID({ issuerUrl: 'https://auth.zewstid.com/realms/zewstid', clientId: 'your_client_id', }); // Validate a JWT token const user = await zewstid.getUser(token); console.log(user);
Express Middleware
import express from 'express'; import { requireAuth } from '@zewstid/node/express'; const app = express(); // Protected route app.get('/api/protected', requireAuth({ issuerUrl: 'https://auth.zewstid.com/realms/zewstid', clientId: process.env.ZEWSTID_CLIENT_ID, }), (req, res) => { res.json({ message: `Hello ${req.user?.name}`, user: req.user, }); } ); app.listen(3000);
API Reference
ZewstID Class
ZewstIDMain client for token validation and user management.
Constructor:
const zewstid = new ZewstID({ issuerUrl?: string; // Default: https://auth.zewstid.com/realms/zewstid clientId?: string; // Your client ID clientSecret?: string; // For confidential operations audience?: string; // Expected JWT audience jwksCacheDuration?: number; // JWKS cache in seconds (default: 3600) debug?: boolean; // Enable debug logging });
Methods:
validateToken(token, options?)
validateToken(token, options?)Validate a JWT access token.
const payload = await zewstid.validateToken(token, { audience: 'my-api', issuer: 'https://auth.zewstid.com/realms/zewstid', maxAge: 3600, // Maximum token age in seconds });
getUser(token)
getUser(token)Validate token and get user information.
const user = await zewstid.getUser(token); // Returns: { id, name, email, roles, ... }
getUserInfo(accessToken)
getUserInfo(accessToken)Get user info from the
/userinfoconst user = await zewstid.getUserInfo(accessToken);
introspectToken(token)
introspectToken(token)Introspect a token (requires client credentials).
const result = await zewstid.introspectToken(token); // Returns: { active: true, scope: '...', ... }
revokeToken(token)
revokeToken(token)Revoke a token (requires client credentials).
await zewstid.revokeToken(token);
getOpenIDConfiguration()
getOpenIDConfiguration()Get OpenID configuration.
const config = await zewstid.getOpenIDConfiguration();
Express Middleware
requireAuth(options)
requireAuth(options)Require authentication for a route.
import { requireAuth } from '@zewstid/node/express'; app.get('/protected', requireAuth({ issuerUrl: 'https://auth.zewstid.com/realms/zewstid', clientId: 'your_client_id', debug: true, }), (req, res) => { // req.user is available // req.token contains the access token res.json({ user: req.user }); } );
Options:
interface ZewstIDMiddlewareOptions { // All ZewstID config options plus: getToken?: (req: Request) => string | null; // Custom token extractor onError?: (error: Error, req: Request, res: Response) => void; // Custom error handler }
optionalAuth(options)
optionalAuth(options)Optional authentication (doesn't block if no token).
app.get('/public', optionalAuth({ clientId: 'your_client_id' }), (req, res) => { if (req.user) { res.json({ message: `Hello ${req.user.name}` }); } else { res.json({ message: 'Hello anonymous' }); } } );
requireRole(role, options?)
requireRole(role, options?)Require specific role(s).
import { requireAuth, requireRole } from '@zewstid/node/express'; app.get('/admin', requireAuth({ clientId: 'your_client_id' }), requireRole('admin'), // Single role (req, res) => { res.json({ message: 'Admin access' }); } ); // Multiple roles (user needs at least one) app.get('/moderator', requireAuth({ clientId: 'your_client_id' }), requireRole(['admin', 'moderator']), (req, res) => { res.json({ message: 'Moderator access' }); } );
requireAllRoles(roles, options?)
requireAllRoles(roles, options?)Require all specified roles.
import { requireAuth, requireAllRoles } from '@zewstid/node/express'; app.get('/super-admin', requireAuth({ clientId: 'your_client_id' }), requireAllRoles(['admin', 'verified']), (req, res) => { res.json({ message: 'Super admin access' }); } );
Advanced Usage
Custom Token Extraction
By default, tokens are extracted from the
Authorization: Bearer <token>requireAuth({ clientId: 'your_client_id', getToken: (req) => { // Extract from cookie return req.cookies.access_token; // Or from query parameter // return req.query.token as string; // Or from custom header // return req.headers['x-api-key'] as string; }, })
Custom Error Handling
requireAuth({ clientId: 'your_client_id', onError: (error, req, res) => { console.error('Auth error:', error); res.status(401).json({ error: 'Custom error message', details: error.message, }); }, })
Validate Token Without Middleware
import { ZewstID } from '@zewstid/node'; const zewstid = new ZewstID({ clientId: 'your_client_id', }); async function checkAuth(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'No token' }); } try { const user = await zewstid.getUser(token); req.user = user; next(); } catch (error) { res.status(401).json({ error: 'Invalid token' }); } }
Role-Based Authorization
function checkRole(role: string) { return (req, res, next) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }); } if (!req.user.roles?.includes(role)) { return res.status(403).json({ error: 'Forbidden', message: `Required role: ${role}`, }); } next(); }; } app.get('/admin', requireAuth({ clientId: 'your_client_id' }), checkRole('admin'), (req, res) => { res.json({ message: 'Admin only' }); } );
Token Introspection
const zewstid = new ZewstID({ clientId: 'your_client_id', clientSecret: 'your_client_secret', }); const result = await zewstid.introspectToken(token); if (result.active) { console.log('Token is valid'); console.log('Scope:', result.scope); console.log('Expires:', new Date(result.exp! * 1000)); } else { console.log('Token is invalid or expired'); }
TypeScript
Full TypeScript support included.
import type { ZewstIDConfig, ZewstIDUser, ZewstIDTokenPayload, ValidateTokenOptions, } from '@zewstid/node'; // Express Request is automatically extended import { Request } from 'express'; function handler(req: Request) { // req.user is typed as ZewstIDUser | undefined // req.token is typed as string | undefined const user: ZewstIDUser | undefined = req.user; }
Environment Variables
ZEWSTID_CLIENT_ID=your_client_id_here ZEWSTID_CLIENT_SECRET=your_client_secret_here ZEWSTID_ISSUER_URL=https://auth.zewstid.com/realms/zewstid
Complete Express Example
import express from 'express'; import { requireAuth, requireRole, optionalAuth } from '@zewstid/node/express'; const app = express(); // Configuration const authConfig = { issuerUrl: process.env.ZEWSTID_ISSUER_URL, clientId: process.env.ZEWSTID_CLIENT_ID!, debug: process.env.NODE_ENV === 'development', }; // Public route app.get('/public', (req, res) => { res.json({ message: 'Public access' }); }); // Optional auth (personalized if authenticated) app.get('/welcome', optionalAuth(authConfig), (req, res) => { if (req.user) { res.json({ message: `Welcome back, ${req.user.name}!` }); } else { res.json({ message: 'Welcome, visitor!' }); } } ); // Protected route app.get('/profile', requireAuth(authConfig), (req, res) => { res.json({ user: req.user, token: req.token, }); } ); // Admin only app.get('/admin', requireAuth(authConfig), requireRole('admin'), (req, res) => { res.json({ message: 'Admin dashboard' }); } ); // Multiple roles (OR logic) app.get('/moderator', requireAuth(authConfig), requireRole(['admin', 'moderator']), (req, res) => { res.json({ message: 'Moderator tools' }); } ); // API endpoint with token validation app.post('/api/data', requireAuth(authConfig), async (req, res) => { // req.user is available // req.token contains the access token // Your business logic here res.json({ success: true, userId: req.user?.id, }); } ); // Error handling app.use((err, req, res, next) => { console.error(err); res.status(500).json({ error: 'Internal server error' }); }); app.listen(3000, () => { console.log('Server running on http://localhost:3000'); });
Fastify Example
Works with Fastify too:
import Fastify from 'fastify'; import { ZewstID } from '@zewstid/node'; const fastify = Fastify(); const zewstid = new ZewstID({ clientId: process.env.ZEWSTID_CLIENT_ID!, }); // Decorator for authentication fastify.decorateRequest('user', null); // Auth hook fastify.addHook('onRequest', async (request, reply) => { const authHeader = request.headers.authorization; if (!authHeader) { return reply.code(401).send({ error: 'No token' }); } const token = authHeader.split(' ')[1]; try { request.user = await zewstid.getUser(token); } catch (error) { return reply.code(401).send({ error: 'Invalid token' }); } }); fastify.get('/protected', async (request, reply) => { return { user: request.user }; }); fastify.listen({ port: 3000 });
Examples
FAQ
Q: How do I get the access token from my frontend? A: Your frontend SDK (@zewstid/react, @zewstid/nextjs) will send it in the
Authorization: Bearer <token>Q: Do I need client secret? A: Only for token introspection and revocation. JWT validation works without it.
Q: How often are JWKS keys refreshed? A: Keys are cached for 1 hour by default. Configure with
jwksCacheDurationQ: Can I use this without Express? A: Yes! Use the
ZewstIDSupport
License
Proprietary and Confidential
Copyright © 2025 Zewst, Inc. All Rights Reserved.
This software is proprietary and confidential. Unauthorized distribution or use is prohibited.
Was this page helpful?
Let us know how we can improve our documentation