Devise-inspired JWT authentication and authorization for Node.js and Express with adapter-based support for MongoDB (Mongoose) and Prisma
npm install node-auth-kitnode-auth-kit is a Devise-inspired authentication and authorization library for Node.js.
It provides JWT authentication, role-based authorization, and an adapter-based architecture so you can plug in MongoDB (Mongoose), Prisma, or other databases without rewriting auth logic.
If youβre tired of rebuilding authentication for every Express app, node-auth-kit gives you clean defaults with full control.
---
Most Node.js authentication libraries are either:
- too low-level, or
- tightly coupled to a specific ORM
node-auth-kit is inspired by Ruby on Rails Devise and focuses on:
- π JWT-based authentication for Express
- π§© Adapter-based database support (DB-agnostic core)
- π Role-based authorization
- βοΈ Config-driven setup with sensible defaults
- π§ Extensible hooks for real-world needs
You bring Express and your database.
node-auth-kit handles authentication, authorization, and security patterns.
---
``bash`
npm i node-auth-kit
or
`bash`
yarn add node-auth-kit
node-auth-kit itself is DB-agnostic. Database drivers / ORMs are optional and only required if you use the corresponding adapter:
- For Mongoose adapter: mongoose@prisma/client
- For Prisma adapter (V2):
---
Create a .env file:
`env`
MONGO_URL=mongodb://localhost:27017/device-auth
DEVICE_AUTH_JWT_SECRET=your-super-secret-key
`ts
import mongoose from 'mongoose';
const UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: ['admin', 'staff', 'user'],
default: 'user',
},
createdAt: {
type: Date,
default: Date.now,
},
});
export const User = mongoose.model('User', UserSchema);
`
`ts
import 'dotenv/config';
import express from 'express';
import mongoose from 'mongoose';
import {
deviceAuth,
mongooseAdapter,
createAuthRouter,
authenticate,
authorize,
} from 'node-auth-kit';
import { User } from './models/User';
const app = express();
app.use(express.json());
// 1. Connect MongoDB
mongoose
.connect(process.env.MONGO_URL)
.then(() => console.log('MongoDB connected'))
.catch(console.error);
// 2. Initialize Device Auth
deviceAuth
.init({
authType: 'jwt',
signupFields: ['email', 'password'],
defaultRole: 'user',
password: {
minLength: 8,
requireNumbers: true,
requireSpecialChars: true,
saltRounds: 10,
},
token: {
accessTokenTtl: '15m',
},
})
.useAdapter(
mongooseAdapter({
userModel: User,
}),
);
// 3. Mount Auth Routes
app.use('/auth', createAuthRouter());
// 4. Example Protected Route
app.get(
'/admin',
authenticate,
authorize('admin'),
(req, res) => {
res.json({ message: 'Admin access granted' });
},
);
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
`
---
The default router created by createAuthRouter() exposes:
| Method | Endpoint | Description |
| ------ | ------------- | ------------------ |
| POST | /auth/register | Register new user |/auth/login
| POST | | Login user |/auth/me
| GET | | Get current user |
You can mount it under any base path (e.g. /api/auth).
`ts`
app.use('/auth', createAuthRouter());
---
Validates the JWT from the Authorization: Bearer header and attaches the user to req.user.
`ts`
app.get('/profile', authenticate, (req, res) => {
res.json(req.user);
});
Restricts access based on user role.
`ts`
app.get('/admin', authenticate, authorize('admin', 'staff'), (req, res) => {
res.json({ message: 'Admin or staff only' });
});
---
Device Auth uses a pluggable adapter architecture, allowing it to work with different databases without changing core logic.
Supported / planned adapters:
| Adapter | Status |
| -------- | -------------------------- |
| Mongoose | β
Stable |
| Prisma | π§ In Progress (V2) |
| TypeORM | β Planned |
The public exports you can use:
- mongooseAdapter β helper for MongoDB via MongooseMongooseAdapter
- β underlying class (advanced use)
---
The central entry point is deviceAuth:
`ts
import { deviceAuth, defaultConfig } from 'node-auth-kit';
deviceAuth.init({
...defaultConfig,
authType: 'jwt',
defaultRole: 'user',
signupFields: ['email', 'password'],
// override anything you need
});
`
Key options:
- authType: currently jwtsignupFields
- : required fields on registrationdefaultRole
- : assigned when no role is providedpassword
- :minLength
- requireNumbers
- requireSpecialChars
- saltRounds
- token
- :accessTokenTtl
- (e.g. 15m, 1h)
The merged configuration is accessible via:
`ts`
const config = deviceAuth.config;
---
Hooks let you run side effects around key lifecycle events without forking core logic.
Supported hook names:
- beforeRegisterafterRegister
- beforeLogin
- afterLogin
-
Register hooks on deviceAuth:
`ts
import { deviceAuth } from 'node-auth-kit';
deviceAuth
.registerHook('beforeRegister', async (createData) => {
// e.g. validate extra fields, audit, etc.
})
.registerHook('afterRegister', async (user) => {
// e.g. send welcome email
})
.registerHook('beforeLogin', async (user) => {
// e.g. check if user is blocked
})
.registerHook('afterLogin', async (user) => {
// e.g. log login event
});
`
Hook errors are intentionally swallowed so they never break core auth flow.
---
Planned for upcoming versions:
- π Refresh tokens
- π± Multi-device sessions
- πͺ Logout (single device / all devices)
- π§ Forgot & reset password
- β
Email verification
- π§ͺ Stable Prisma adapter
- π§ Additional hooks & lifecycle events
---
`bash`
npm test
Postman collection β _coming soon_.
---
Contributions are welcome!
1. Fork the repository
2. Create a new branch
`bash``
git checkout -b feature/my-feature
3. Commit your changes
4. Push to your branch
5. Open a Pull Request
---
MIT License Β© 2025