wezt-authentication v1.0.2
WEZT-AUTHENTICATION
Simplify user authentication on your express app! π©βπΌπ¨βπΌ OBS: This package is not recomended if you need a high-level of customization in your app's authentication system. We'll keep working on customization but it is not our focus on development. Our mission is to deliver a reliable, safe and simple way to register and manage your users.
Installation
$ npm i wezt-authentication
Importing
const Authentication = require('wezt-authentication');
// ES6
import Authentication, {
AuthenticationError,
/**
* wezt.AuthenticationError, extends Error
* Error class that receives a status code on constructor. If you're willing to extend your authentication logic, you should create your own error classes extending this AuthenticationError.
* Usage #1: throw new AuthenticationError('Unknown parameter', 400);
* Usage #2: class BadRequestError extends AuthenticationError {
* constructor(message?: string) {
* super(message || "Unknown parameter", 400);
* {...}
* }
* }
* throw new BadRequestError();
* */
Controller,
/**
* wezt.Controller
* When creating other controllers for your applications, extend/implement this interface.
* Usage #1: const PostController: Controller = {
* store: (req: Request, res: Response) => { ... },
* ...
* }
* Usage #2: interface IPostController extends Controller { ... }
* Usage #3: class PostController implements Controller {
* store(req: Request, res: Response) {
* ...
* };
* ...
* }
* */
} from 'wezt-authentication';
Documentation
Parameters
References to used packages: express mongoose express-session nodemailer
Authentication({
app,
/**
* express.Application
* Reference to an express application.
* Ex: express()
* */
connection,
/**
* mongoose.Connection
* Reference to a mongoose connection.
* Ex: mongoose.createConnection(uri, options)
* */
nodemailer: {
// undefined | object
// Only required when routes is set as an object or as true.
smtp,
/**
* nodemailer.SMTPTransport.Options
* SMTP Transporter configuration for sending mails.
* Ex: {
* service: 'gmail',
* auth: {
* user: 'yourEmail@gmail.com',
* pass: 'yourPassword',
* }
* }
* */,
mail,
/**
* nodemailer.SendMailOptions
* Options object to customize your password recovery mail.
* There is some placeholders you can insert on "text" property to retrieve some useful information.
* Currently supported placeholders:
* {{code}} legible 6-digits code
* {{token}} one-time use jsonwebtoken to recover password
* Ex: {
* from: 'yourEmail@gmail.com',
* subject: 'Password recovery',
* text: 'There is your recovery code: {{code}}. Click on this link to redirect to the password recovery page: https://yourdomain.com/recover/{{token}}/{{code}}',
* }
* */
},
sessionOptions,
/**
* session.SessionOptions
* Options object to create a session middleware using express-session
* Ex: {
* secret: "yourSecretKey",
* cookie: {
* maxAge: 30 * 24 * 60 * 60 * 1000
* },
* name: "SESSID",
* resave: false,
* saveUninitialized: false,
* }
* */
roles,
/**
* string[]
* Array of strings containing all possible roles for users.
* Ex: ["Admin", "Manager", "Client"]
* */
administrativeRoles,
/**
* string[]
* Array of strings containing all administrative roles, that have full access to user management.
* Ex: ["Admin", "Client"]
* */
defaultRole,
/**
* string
* String that specifies the default role assigned to a
* created or registered user.
* Ex: "Client"
* */
routes,
/**
* undefined | boolean | object
* Whether you want or not to automatically set routes for your application.
* Setting this as false will require you to set your routes and paths manually.
* Defaults to false.
* Ex: false | {
* authPrefix: '/', // default: /auth
* profilePrefix: '/me', // default: /profile
* usersPrefix: '/clients'
* }
* */
userSchema,
/**
* undefined | mongoose.Schema
* Optional property to set your custom mongoose user schema. By modifying the user schema, you may need to overwrite the authentication logic with your own code.
* Ex: new mongoose.Schema({
* name: {
* type: String,
* required: true,
* },
* username: {
* type: String,
* required: true,
* unique: true,
* },
* password: {
* type: String,
* required: true,
* },
* }, { timestamps: true })
* */
})
Return
const {
authorize,
/**
* express.RequestHandler
* Middleware to authenticate and authorize users based on role.
* "roles" parameter is optional. When undefined, it only authenticates the user.
* Usage #1: routes.post('/post/:postId/comments, authorize(), CommentController.store);
* Usage #2: routes.post('/products, authorize(['Admin', 'Manager']), ProductsController.store);
* */
mustNotBeAuthenticated,
/**
* express.RequestHandler
* Middleware to ensure the user accessing the route is not authenticated. Useful to prevent session overwrites and other exploitations.
* Usage: routes.post('/login', mustNotBeAuthenticated(), MyOwnAuthController.login);
* */
errorHandler,
/**
* express.ErrorRequestHandler
* A basic Error handler to catch and log errors. Be sure to use this middleware after using all your routes!
* routes.use('/posts', postsRoutes);
* {...}
*
* app.use('/api', routes);
* app.use(errorHandler);
*
* app.listen(...);
* */
UserController,
/**
* wezt.Controller
* Controller containing administrative CRUD for the User Model. Use this when setting "routes" as false, and when willing to overwrite controller functions with your own code. Be sure to not allow common users to have access to this routes, as they have full controll over all users on database!
* Usage: const { UserController, routes, authorize } = Authentication({...config, routes: false });
* UserController.index = (req: express.Request, res: express.Response) => {
* ...yourOwnLogic
* }
* routes.post("/Your/Own/Path", [...YourMiddlewares, authorize('Admin')], UserController.store);
* routes.post("/Your/Own/Path", [...YourMiddlewares, authorize('Admin')], UserController.index);
* */
AuthController,
/**
* wezt.IAuthController, extends wezt.Controller
* Controller containing profile CRUD and authentication logic, such as login, logout, register and password recovery.
* Usage: Same as above
* */
User,
/**
* wezt.UserModel<UserDocument>, extends mongoose.Model
* Model that manipulates the "users" collection on mongodb. Only useful when extending the authentication logic.
* Usage: await User.create({...});
* */
transporter: Mail,
/**
* nodemailer.Mail
* Use this transporter if your app will need to send mails in other routes.
* Usage: See nodemailer docs
* */
routes: Router,
/**
* express.Router
* When config property "routes" is set as true, use this routes to include the rest of your application.
* Usage: const { routes } = Authentication(config);
*
* routes.use('/posts', PostController);
* routes.use('/products', ProductController);
*
* app.use('/api', routes);
* */
} = Authentication(config);
Basic usage
import Authentication from 'wezt';
import express from 'express';
import mongoose from 'mongoose';
const app = express();
const connection = mongoose.createConnection('mongodb://localhost:27017/wezt-test', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
});
const { errorHandler, routes } = Authentication({
app,
connection,
routes: true,
roles: ['Admin', 'User'],
administrativeRoles: ['Admin'],
defaultRole: 'User',
nodemailer: {
smtp: {
service: 'gmail',
auth: {
user: '<youremail@gmail.com>',
pass: '<yourpassword>',
},
},
mail: {
from: '<youremail@gmail.com>',
subject: 'Password recovery',
text: 'There is your recovery code: {{code}}. Click on this link to redirect to the password recovery page: http://yourdomain.com/{{token}}/{{code}}.',
},
},
sessionOptions: {
secret: '<secret>',
cookie: {
maxAge: 30 * 24 * 60 * 60 * 1000,
},
name: '<session cookie name>',
resave: false,
saveUninitialized: false,
},
});
app.use('/api', routes);
app.use(errorHandler);
const port = process.env.PORT || 3333;
app.listen(port, (err) => {
if(err) throw err;
console.log(`Connected on port ${port}`);
});
Generated Endpoints
Every POST/PUT route does NOT accept unknown properties on body object.
POST /auth/login
Authorization: everyone
Body { email: string; password: string; }
Return object 200 - { user: UserDocument; } 400, 401, 404, 500 0- { error: string; }
Result Generates a session and returns a cookie via Headers.
POST /auth/logout
Authorization: authenticated users 204 - No Content; 401 - { error: string; }
Result Destroys an User Session.
POST /auth/register
Authorization: not authenticated users
Body UserObject { email: string; username: string; password: string; }
Return object 201 - { user: UserDocument; } 400, 409, 500 - { error: string; }
Result Generates a new User and return it as an object, generates a session and return a cookie via Headers.
POST /auth/recover
Authorization: not authenticated users
Body { email: string; }
Return object 200 - { token: string; (JsonWebToken) } 400, 404, 500 - { error: string; }
Result Generates a JsonWebToken signed with a 6-Digit code that is sent to the user's email.
GET /auth/validateToken/:token/:code
Authorization: not authenticated users
Parameters { token: string; (JsonWebToken) code: string; (6-Digit code) }
Return object 204 - No Content; 400, 401, 500 - { error: string; }
Result Returns a 204 status code with no content if the given code successfully decrypts the given token.
POST /auth/reset/:token/:code
Authorization: not authenticated users
Parameters { token: string; (JsonWebToken) code: string; (6-Digit code) }
Body { password: string; }
Return object 200 - { user: UserDocument; } 400, 401, 500 - { error: string; }
Result Modifies user's password, generates a session and return a cookie via Headers.
GET /users
Authorization: administrativeRoles
Query { username?: string; email?: string; limit?: string; default = 20 page?: string; default = 1 sortBy?: string; sort?: 'asc' | 'desc'; default = 'asc' }
Return object 200 - { docs: UserDocument[]; totalDocs: number; limit: number; totalPages: number; page: number; pagingCounter: number; hasPrevPage: boolean; hasNextPage: boolean; prevPage: number | null; nextPage: number | null; } 400, 401, 403 - { error: string; }
Result Returns an array containing several users that satisfies the given query.
GET /users/:id
Authorization: administrativeRoles
Parameters { id: mongoose.Types.ObjectId; }
Return object 200 - { user: UserDocument; } 400, 401, 403, 404 - { error: string; }
Result Returns the User document that matches the given Id.
POST /users
Authorization: administrativeRoles
Body { username: string; email: string; password: string; role?: string; }
Return object 200 - { user: UserDocument; } 400, 401, 403 - { error: string; }
Result Creates a new user.
PUT /users/:id
Authorization: administrativeRoles
Parameters { id: mongoose.Types.ObjectId; }
Body { username?: string; email?: string; password?: string; role?: string; }
Return object 200 - { user: UserDocument; } 400, 401, 403, 404 - { error: string; }
DELETE /users/:id
Authorization: administrativeRoles
Parameters { id: mongoose.Types.ObjectId; }
Return object 204 - No content 400, 401, 403, 404 - { error: string; }
GET /profile
Authorization: authenticated user
Return object 200 - { user: UserDocument; } 401, 404, 500 - { error: string; }
PUT /profile
Authorization: authenticated user
Body { username?: string; email?: string; password?: string; role?: string; }
Return object 200 - { user: UserDocument; } 400, 401, 500 - { error: string; }
DELETE /profile
Authorization: authenticated user
Return object 204 - No Content 401, 404 - { error: string; }