A versatile and secure authentication module for Node.js applications.
- Support for multiple storage methods: MongoDB, encrypted file, or in-memory
- User registration and login
- Password hashing with bcrypt
- JWT token verification
- Two-factor authentication (2FA) with QR codes
- Login attempt limiting and user locking
- Password reset and 2FA management
Install the module via npm:
npm install seamless-auth
Import the desired version of the authenticator:
// For MongoDB support
const Authenticator = require('seamless-auth/mongodb');
// For encrypted file storage
const Authenticator = require('seamless-auth/file');
// For in-memory storage
const Authenticator = require('seamless-auth/memory');
If you use MongoDB, you NEED to make a schema with these values as a minimum. You can add as many fields as you need. (e.g., phone number, address)
const DB_SCHEMA = {
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
loginAttempts: { type: Number, default: 0 },
locked: { type: Boolean, default: false },
emailCode: { type: String, default: "", required: false, unique: true },
wants2FA: { type: Boolean, default: false },
secret2FA: String
}
Initialize the authenticator with the required parameters:
// File / Memory Storage
const auth = new Authenticator();
// MongoDB Storage
const auth = new Authenticator(
MONGODB_STRING,
USER_SCHEMA
)
// There are a lot more options available below which are not required.
These contain the default inputs and CAN be changed by auth.QR_LABEL = "something else";
this.QR_LABEL = "Authenticator";
this.rounds = 12;
this.JWT_SECRET_KEY = "changeme";
this.JWT_OPTIONS = { expiresIn: "1h" };
this.maxLoginAttempts = 13;
this.maxLoginAttempts = this.maxLoginAttempts - 2;
this.DB_FILE_PATH = "./users.db";
this.DB_PASSWORD = "changeme";
this.users = [];
this.OTP_ENCODING = 'base32';
this.lockedText = "User is locked";
this.OTP_WINDOW = 1;
// How many OTP codes can be used before and after the current one (usefull for slower people, recommended 1)this.INVALID_2FA_CODE_TEXT = "Invalid 2FA code";
this.REMOVED_USER_TEXT = "User has been removed";
this.USERNAME_ALREADY_EXISTS_TEXT = "This username already exists";
this.EMAIL_ALREADY_EXISTS_TEXT = "This email already exists";
this.USERNAME_IS_REQUIRED="Username is required";
this.ALLOW_DB_DUMP = false;
// Allowing DB Dumping is disabled by default can be enabled by setting ALLOW_DB_DUMP to true after initializing your class
Registers a new user.
Logs in a user.
Retrieves user information.
Retrieves user information based on a custom search criteria (like email, username,...)
Verifies a JWT token.
Verifies a 2FA code. Useful for reverifying user identity when accessing sensitive functions
Resets a user's password.
Changes the number of login attempts for a user.
Locks a user account.
Unlocks a user account.
Removes 2FA for a user.
Adds 2FA for a user.
Generates a OTP so the user can use passwordless login, using their email
Verifies the OTP from the user and responds with a valid jwt_token
Revokes all existing JWT token for that user
Removes a user.
Checks if a user is authenticated using the token from the cookies from the request and provides the user as req.user
Encrypted File
const Authenticator = require('seamless-auth/file.js');
const auth = new Authenticator(
'MyApp',
12,
'my_secret_key',
{ expiresIn: '1h' },
5,
'./users.db',
'db_password'
);
Memory storage (ephemeral)
import Authenticator from 'seamless-auth/memory'
let USERS = [] // If you want to have existing users, add here
const auth = new Authenticator(
'MyApp',
12,
'your_jwt_secret',
{ expiresIn: '1h' },
5,
USERS
);
const Authenticator = require('seamless-auth/file');
const auth = new Authenticator(
'MyApp',
12,
'your_jwt_secret',
{ expiresIn: '1h' },
5,
'./users.db',
'db_password'
);
// Register a new user
const registerResult = await auth.register({
email: '[email protected]',
password: 'secure_password',
wants2FA: true
});
console.log(registerResult);
const loginResult = await auth.login('[email protected]', 'secure_password', '123456');
console.log(loginResult);
// OR
const emailCode = await auth.registerEmailSignin('[email protected]'); // Sent code to users email or phone number
token = await auth.verifyEmailSignin(emailCode) // emailCode is that code that the user sends back, can be because a link he clicked or just when he filled the code in
console.log(token.jwt_token); // It responds with a JSON WEB TOKEN
await auth.revokeUserTokens(userId)
Check authentication
await Auth.isAuthenticated(req)
if (isAuth) // do something
middleware to check authentication
const checkAuth = async (req, res,next) => {
let isAuth = await Auth.isAuthenticated(req)
if (!isAuth) return res.redirect('/login')
next()
}
import Authenticator from "../mongodb.js";
let DB_SCHEMA = {
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
loginAttempts: { type: Number, default: 0 },
locked: { type: Boolean, default: false },
wants2FA: { type: Boolean, default: false },
secret2FA: String
}
let connectionString = "CONNECTIONSTRING" // The connection string for MongoDB
const auth = new Authenticator('MyApp', 12, 'your_jwt_secret', { expiresIn: '1 ' }, 5, connectionString, DB_SCHEMA);
Mozilla Public License, v. 2.0
Contributions are welcome! Please open an issue or submit a pull request.
For questions or support, please open an issue on the GitHub repository.