Authentication solution for Express

Overview

Lockit

Build Status NPM version Dependency Status

Lockit is an authentication solution for Express. Check out the demo.

It consists of multiple single purpose modules:

Table of contents

Quickstart

  1. Create new Express app.

express

  1. Install Lockit and sessions via npm.

npm install && npm install lockit cookie-session --save

  1. Use lockit and cookie-session in your Express app.js.
var cookieSession = require('cookie-session');
var Lockit = require('lockit');
var lockit = new Lockit();

...
app.use(cookieSession({
  secret: 'my super secret String'
}));
app.use(lockit.router);
  1. Go to localhost:3000/signup

By default Lockit uses an in-memory SQLite database. So you don't have to set up any db. Lockit will just work. Check out the default example.

For production use a persistent data store!

Full installation

  1. Install and require

npm install lockit --save

var config = require('./config.js');
var Lockit = require('lockit');

var app = express();

// express middleware
// ...
// sessions are required
app.use(cookieParser());
app.use(cookieSession({
  secret: 'your secret here'
}));

var lockit = new Lockit(config);

app.use(lockit.router);

// you now have all the routes like /login, /signup, etc.
// and you can listen on events. For example 'signup'
lockit.on('signup', function(user, res) {
  console.log('a new user signed up');
  res.send('Welcome!');   // set signup.handleResponse to 'false' for this to work
});
  1. Add styles

Views are built with bootstrap. You can use your own ones though! Use Bootstrap CDN and add the following line to your layout.jade

link(rel='stylesheet', href='//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css')
  1. Install database adapter

npm install lockit-[DB]-adapter where [DB] can be

Database Command
CouchDB npm install lockit-couchdb-adapter
MongoDB npm install lockit-mongodb-adapter
SQL (PostgreSQL, MySQL, MariaDB or SQLite) npm install lockit-sql-adapter

If you use a SQL database you also have to install the connector.

npm install pg       # for postgres
npm install mysql    # for mysql
npm install sqlite3  # for sqlite
npm install mariasql # for mariasql

Configuration

You need a config.js somewhere in your app.

Database connection

Add the database connection string to your config.js.

// database settings for CouchDB
exports.db = 'http://127.0.0.1:5984/';        // connection string for database

// or if you want to use MongoDB
// exports.db = {
//   url: 'mongodb://127.0.0.1/',
//   name: 'test',
//   collection: 'users'  // collection name for MongoDB
// };

// PostgreSQL
// exports.db = {
//   url: 'postgres://127.0.0.1:5432/',
//   name: 'users',
//   collection: 'my_user_table'  // table name for SQL databases
// };

// MySQL
// exports.db = {
//   url: 'mysql://127.0.0.1:3306/',
//   name: 'users',
//   collection: 'my_user_table'
// };

// SQLite
// exports.db = {
//   url: 'sqlite://',
//   name: ':memory:',
//   collection: 'my_user_table'
// };

Sending emails

By default the email service is stubbed and no emails are sent. That means that you won't receive any signup and password reset tokens. You have to look them up in your database and call the routes manually (e.g. /signup/:token). To send emails you need an email server and you have to change the settings in your config.js:

  • emailType - usually nodemailer-smtp-transport
  • emailSettings - see nodemailer for more information

With mailgun you can send up to 10,000 emails per month for free.

exports.emailType = 'nodemailer-smtp-transport';
exports.emailSettings = {
  service: 'Mailgun',
  auth: {
    user: '[email protected]',
    pass: 'secret-password'
  }
};

Custom views

Lockit comes with built-in views which are based on Bootstrap. If you want to use your own custom views you can. It is dead simple.

Put them into your views folder, for example views/lockit/myLogin.jade. Then edit your config.js and set the path to your custom view.

exports.login = {
  route: '/login',
  logoutRoute: '/logout',
  views: {
    login: 'lockit/myLogin.jade',
    loggedOut: 'lockit/myLogoutSuccess.jade'
  }
};

The only thing you have to keep in mind is the structure. The login.views.login view, for example, needs a form element with two input fields. The method has to be POST and action should point to your login.route. The input fields have to have the names login and password. If something went wrong during the login process you'll get an error variable that you can use in your template.

Here is a minimalistic example for an alternative myLogin.jade.

extend /layout

block content
  h1 Login
  form(action="/login", method="POST")
    div
      label(for="login") Email or Username
      input(type="text", id="login", name="login", placeholder="Your email or username")
    div
      label(for="password") Password
      input(type="password", id="password", name="password", placeholder="Your password")
    if error
      p #{error}
    input(type="submit", value="Login")

For more information about each view see the views folder inside the different repositories. Make sure your view extends /layout which is different to your normal views. They extend layout without the slash. This is required to find the view.

Events

Lockit emits the most important events for user authentication. Those are

  • signup
  • login
  • logout
  • delete

You can use these events to intercept requests and implement some custom logic, like getting the gravatar before sending a response to the client.

signup

A new user signed up. The callback function has two arguments.

  • user is an object and contains information about the new user, like user.name or user.email.
  • res is the standard Express.js res object with methods like res.render and res.send. If you've set signup.handleResponse to false Lockit will not handle the response for you. You therefore have to send the response back to the client manually or otherwise it will wait forever.
lockit.on('signup', function(user, res) {
  // ...
});
login

A user logged in. Callback function this time has three arguments.

  • user is again the JSON object containing info about that particular user.
  • res is the normal Express.js response object with all properties and methods.
  • target is the redirect target route after a successful login, i.e. /settings
lockit.on('login', function(user, res, target) {
  // ...
});
forgot::sent

A user forgot the password and an email has been sent. Callback function has two arguments.

  • user is again the JSON object containing info about that particular user.
  • res is the normal Express.js response object with all properties and methods.
lockit.on('forgot::sent', function(user, res) {
  // ...
});
forgot::success

User has created a new password. Callback function has two arguments.

  • user is again the JSON object containing info about that particular user.
  • res is the normal Express.js response object with all properties and methods.
lockit.on('forgot::success', function(user, res) {
  // ...
});
logout

A user logged out. Same as above without the target string.

lockit.on('logout', function(user, res) {
  // ...
});
delete

A user deleted an account. Same callback as above.

lockit.on('delete', function(user, res) {
  // ...
});

REST API

In a single page application (SPA) all routing and template rendering is done on the client. Before version 0.5.0 Lockit caught relevant routes, like /login or /signup, and did the entire rendering on the server.

Starting with version 0.5.0 you're able to use Lockit as a REST API and communicate via JSON. All you have to do is set exports.rest in your config.js.

exports.rest = {
  // set starting page for single page app
  index: 'public/index.html',

  // use view engine (render()) or send static file (sendfile())
  useViewEngine: false
}

With REST enabled all default routes get a /rest prefix so you can catch /login on the client. To allow for true page refreshes (i.e. user is at /login and refreshes the page) all routes on the server, like /login and /signup, send the rest.index view to the client. From there your SPA has to take over.

Here is a short example how the process works.

  1. User sends GET request for /login
  2. Server has a route handler for this request and sends index.html back
  3. Client router takes over and renders /login page
  4. User enters credentials and submits the form
  5. Client controller catches submit and sends POST via AJAX request to /rest/login
  6. Server handles POST request and validates user credentials
  7. Server sends status code 200 or some JSON with error message
  8. Client reacts to JSON from server and redirects on success or shows error

I've built a simple example using AngularJS on the client side.

Sample config

If you want to go crazy and customize all the things you can:

// name for subject and email content
exports.appname = 'lockit - Test App';

// url for proper link generation
exports.url = 'http://localhost:3000';

// email settings (same as nodemailer)
exports.emailType = 'nodemailer-stub-transport';
exports.emailSettings = {
  service: 'none',
  auth: {
    user: 'none',
    pass: 'none'
  }
};

// whenever a library uses request under the hood (like nano in lockit-couchdb-adapter)
// the following values will be used
exports.request_defaults = {
  // proxy: 'http://someproxy'
};

// email template from npm
exports.emailTemplate = 'lockit-template-blank';

// render views or json for single page apps
exports.rest = false;

// or if you want to use rest
// exports.rest = {
//
//   // set starting page for single page app
//   index: 'public/index.html',
//
//   // use view engine (render()) or send static file (sendfile())
//   useViewEngine: false
//
// }

// signup settings
exports.signup = {
  route: '/signup',
  tokenExpiration: '1 day',
  views: {
    signup: '',         // input fields 'name', 'email' and 'password' | local variable 'error' | POST /'signup.route'
    linkExpired: '',    // message link has expired | input field 'email' | POST /'signup.route'/resend-verification
    verified: '',       // message email is now verified and maybe link to /'login.route'
    signedUp: '',       // message email has been sent => check your inbox
    resend: ''          // input field 'email' | local variable 'error' | POST /'signup.route'/resend-verification
  },
  handleResponse: true  // let lockit handle the response after signup success
};

// login settings
exports.login = {
  route: '/login',
  logoutRoute: '/logout',
  views: {
    login: '',          // input fields 'login' and 'password' | POST /'login.route' | local variable 'error'
    loggedOut: ''       // message that user logged out
  },
  handleResponse: true  // let lockit handle the response after login/logout success
};

// forgot password settings
exports.forgotPassword = {
  route: '/forgot-password',
  tokenExpiration: '1 day',
  views: {
    forgotPassword: '', // input field 'email' | POST /'forgotPassword.route' | local variable 'error'
    newPassword: '',    // input field 'password' | POST /'forgotPassword.route'/#{token} | local variable 'error'
    changedPassword: '',// message that password has been changed successfully
    linkExpired: '',    // message that link has expired and maybe link to /'forgotPassword.route'
    sentEmail: ''       // message that email with token has been sent
  }
};

// delete account settings
exports.deleteAccount = {
  route: '/delete-account',
  views: {
    remove: '',         // input fields 'name', 'phrase', 'password' | POST /'deleteAccount.route' | local variable 'error'
    removed: ''         // message that account has been deleted
  },
  handleResponse: true  // let lockit handle the response after delete account success
};

// lock account
// show warning after three failed login attempts
exports.failedLoginsWarning = 3;
// lock account after five failed login attempts
exports.failedLoginAttempts = 5;
// lock account for 20 minutes
exports.accountLockedTime = '20 minutes';

// public email address of your app
exports.emailFrom = '[email protected]';

// email signup template
exports.emailSignup = {
  subject: 'Welcome to <%- appname %>',
  text: [
    '<h2>Hello <%- username %></h2>',
    'Welcome to <%- appname %>.',
    '<p><%- link %> to complete your registration.</p>'
  ].join(''),
  linkText: 'Click here'
};

// email already taken template
exports.emailSignupTaken = {
  subject: 'Email already registered',
  text: [
    '<h2>Hello <%- username %></h2>',
    'you or someone else tried to sign up for <%- appname %>.',
    '<p>Your email is already registered and you cannot sign up twice.',
    ' If you haven\'t tried to sign up, you can safely ignore this email. Everything is fine!</p>',
    '<p>The <%- appname %> Team</p>'
  ].join('')
};

// resend signup template
exports.emailResendVerification = {
  subject: 'Complete your registration',
  text: [
    '<h2>Hello <%- username %></h2>',
    'here is the link again. <%- link %> to complete your registration.',
    '<p>The <%- appname %> Team</p>'
  ].join(''),
  linkText: 'Click here'
};

// forgot password template
exports.emailForgotPassword = {
  subject: 'Reset your password',
  text: [
    '<h2>Hey <%- username %></h2>',
    '<%- link %> to reset your password.',
    '<p>The <%- appname %> Team</p>'
  ].join(''),
  linkText: 'Click here'
};

Features

  • responsive html email template: lockit-template-blank
  • support for wide range of databases out of the box
  • email address verification
  • account locking after too many failed login attempts
  • verification link expiration
  • failed login tracking
  • /login redirection when user is unauthorized
  • password hash generation with bcrypt
  • unit tests for all modules
  • serves proper HTML views or only JSON
  • events for most important happenings login, logout, signup and delete
  • implementation of lots of best pratices

Routes included

From lockit-signup

  • GET /signup
  • POST /signup
  • GET /signup/:token
  • GET /signup/resend-verification
  • POST /signup/resend-verification

From lockit-login

  • GET /login
  • POST /login
  • POST /login/two-factor
  • GET /logout

From lockit-forgot-password

  • GET /forgot-password
  • POST /forgot-password
  • GET /forgot-password/:token
  • POST /forgot-password/:token

From lockit-delete-account

  • GET /delete-account
  • POST /delete-account

Test

grunt

License

MIT

Comments
  • Include an optional restRoute config

    Include an optional restRoute config

    So that I may override in my own configs to point to my own main route. /public directory is often used as a grunt build directory so a possibly dev config route is useful.

    opened by ChromeQ 18
  • Can't find Python executable

    Can't find Python executable "python"

    Hello.

    I am getting this error. I have tried installing python modules but I have a strong feeling that this isn't going to help and that I have to do something outside of node.js

    This is an image of the error: Any help would be appreciated. Thank you!

    screen

    opened by georgeportillo 12
  • Waterline adapter

    Waterline adapter

    This is pretty neat, however the way the DB configurations are currently setup I found it quite tricky to make it work with my Sails.js site using the Waterline ORM. Basically I could bypass the ORM to connect directly separately to Mongo or Postgres or whatever the ORM adapter in waterline is pointed to as well. But I'd much prefer a lockit waterline adapter and just let the ORM to deal with those details.

    Just a thought,

    opened by nmcclay 8
  • Why is there no unique index on username and email address?

    Why is there no unique index on username and email address?

    I noticed on my mongodb installation for lockit that an index is set for user's id. That's good. However, lockit does not seem to set an unique index for username and email address which it should in my opinion or is there a specific reason not to do so?

    opened by valnub 7
  • SMTP configuration not being passed to nodemailer

    SMTP configuration not being passed to nodemailer

    It seems that the emailSettings are not being passed on to the smtpTransport, since I specified them and digging in to Email.prototype.send, line 58, the emailSettings are not being passed on and, due to that, I got an ECONNREFUSED:

    // send email with nodemailer
    var transporter = nodemailer.createTransport(that.transport(options)); // options are not including my emailSettings
    transporter.sendMail(options, function(err, res){
      if(err) return done(err);
      transporter.close(); // shut down the connection pool, no more messages
      done(null, res);
    });
    
    opened by rbaprado 7
  • When does a login session expire?

    When does a login session expire?

    I see no configuration option in the documentation for this... What is the default expire time for each session?

    Also, I noticed that if you log in twice with the same account on two different browsers (let's call them session1 and session2) and you log out from session2, then you will stay logged in in session1. Is this on purpose? I think it's a security problem.

    opened by valnub 5
  • How to run the couchdb example?

    How to run the couchdb example?

    I have tried asin this post http://stackoverflow.com/questions/25320313/couchdb-with-nodejs-authentication-solution and as the instructions on the readme, and i cant keep it running

    opened by Esauromano 5
  • Making the cookie persistant

    Making the cookie persistant

    Hi all, I am working on my first nodejs project so I'm still pretty new to all this, but I really enjoy working with lockit.

    I'm trying to make the login persistant by changing the cookie expiration date, and can't find the solution... Should it be added as a config var ?

    opened by charleshaa 5
  • Cannot get full example to work

    Cannot get full example to work

    I tried the "full example" code:

    var config = require('./config.js');
    var Lockit = require('lockit');
    
    var app = express();
    
    app.use(cookieParser());
    app.use(cookieSession({
      secret: 'secret'
    }));
    
    var lockit = new Lockit(config);
    
    app.use(lockit.router);
    
    // you now have all the routes like /login, /signup, etc.
    // and you can listen on events. For example 'signup'
    lockit.on('signup', function(user, res) {
      console.log('a new user signed up');
      res.send('Welcome!');   // set signup.handleResponse to 'false' for this to work
    });
    

    When I started the server it complained that express was undefined, so I installed express via npm and added:

    var express = require('express');
    

    and changed:

    app.use(cookieParser());
    app.use(cookieSession({
      secret: 'secret'
    }));
    

    to this:

    app.use(express.cookieParser());
    app.use(express.cookieSession({
      secret: 'secret'
    }));
    

    But now I get this. What's wrong?

    lockit no email config found. Check your database for tokens.
    /Users/valmar/dev/node/todolist/node_modules/lockit/node_modules/lockit-signup/index.js:40
      router.get(route, this.getSignup.bind(this));
            ^
    TypeError: Cannot read property 'get' of undefined
        at new module.exports (/Users/valmar/dev/node/todolist/node_modules/lockit/node_modules/lockit-signup/index.js:40:9)
        at new module.exports (/Users/valmar/dev/node/todolist/node_modules/lockit/index.js:41:16)
        at Object.<anonymous> (/Users/valmar/dev/node/todolist/server.js:12:14)
        at Module._compile (module.js:460:26)
        at Object.Module._extensions..js (module.js:478:10)
        at Module.load (module.js:355:32)
        at Function.Module._load (module.js:310:12)
        at Function.Module.runMain (module.js:501:10)
        at startup (node.js:129:16)
        at node.js:814:3
    
    opened by valnub 4
  • Custom Adapter

    Custom Adapter

    Hi @zemirco. Awesome project! This is exactly what I've been looking for.

    I was wondering if it would be possible to support a the ability to specify a custom adapter module? It looks like the getDatabase function restricts the possible adapter modules to the existing lockit-*-adapter family. My use case is I have a project that uses knex to access a postgress database and I'd like to keep all of my table migrations managed in the same place. So I'm a little wary about letting the lockit-sql-adapter sync a table under the hood with sequelize.

    opened by bmac 4
  • Error: Cannot find module 'xtend'

    Error: Cannot find module 'xtend'

    I've tried to get the example app up and running but keep getting the following message:

    Error: Cannot find module 'xtend'

    Node v0.10.24 NPM v1.3.21 grunt-cli v0.1.11

    Thanks.

    opened by jayfallon 4
  • OAuth authentication

    OAuth authentication

    Hello, is there a known / easy way to use OAuth based authentication? e.g. https://github.com/dgrubelic/vue-authenticate/blob/master/example/server.js

    opened by Mihailoff 0
  • Cannot find module:  lockit-template-blank

    Cannot find module: lockit-template-blank

    It's really really easy to get this error, including if you just make a new express app using defaults and try the quick-start with lockit as per the instructions in lockit's readme:

    npm start

    lockit no db config found. Using SQLite. lockit no email config found. Check your database for tokens.

    /signup

    ..fill in the form and submit it..

    ->

    Unhandled rejection Error: Cannot find module 'lockit-template-blank'
        at Function.Module._resolveFilename (module.js:338:15)
        at Function.Module._load (module.js:280:25)
        at Module.require (module.js:364:17)
        at require (module.js:380:17)
        at new module.exports (/Users/dhall/projects/myapp/node_modules/lockit/node_modules/lockit-signup/node_modules/lockit-sendmail/index.js:16:19)
    
    opened by dennishall1 1
  • Option to key/index off of email instead of username

    Option to key/index off of email instead of username

    It looks like name is intended to be username, and not the user's name, as it must be unique. Email must also be unique. It is common, and arguably a better user experience to only require email, as it already must be unique, instead of requiring two fields that have to be unique. Also, a user may forget the username they invented for your site---because it has to be unique for your site, so someone else could have taken the one they wanted---but they are less likely to forget their email address, and if email address requires verification, then nobody else can take their email address on your site.

    Personally, I'd much rather just treat email address as username, and dispense with username field.

    I suppose I could hack it by creating a hidden field and have javascript copy the email address into the username field just before form submit ... but I'd rather not even have a username field in my database.

    Nope, can't hack it that way. Gives error: "Username may not contain any non-url-safe characters." .. but you can still hack it, just with a hack that looks worse by the minute .. javascript runs encodeURIComponent on the email address first, or you might just replace @ with -at- .. then pastes it into the hidden field.

    opened by dennishall1 0
  • Document / implement -- Custom error messages

    Document / implement -- Custom error messages

    Much of lockit is configurable. Thanks for that!

    However, there are a few things that are still hard-coded, such as some of the error messages.

    It would be great if these were also customizable.

    opened by dennishall1 0
  • Document / Implement if needed - More fields for a user signing up

    Document / Implement if needed - More fields for a user signing up

    It would be beneficial to document or implement the ability to have more fields during user signup. Frequently, it would be preferable to have firstname + lastname instead of simply name.

    opened by dennishall1 0
Owner
Mirco Zeiss
IT Architect
Mirco Zeiss
An easy to use authentication system that can easily be built in to your Express + HBS web apps.

yoAuth An easy to use authentication system that can easily be built in to your Express + HBS web apps. Currently only supports local authentication,

null 2 Jan 21, 2022
Simple, unobtrusive authentication for Node.js.

Passport Passport is Express-compatible authentication middleware for Node.js. Passport's sole purpose is to authenticate requests, which it does thro

Jared Hanson 21k Jan 7, 2023
A small project with 3 accounts mapped to 3 resources using auth0 as an authentication service.

Auth0WithExpressJS Quickstart install dependencies for backend and start backend cd Auth0WithExpressJS\Back && npm start install dependencies for fron

RYMND 16 Aug 21, 2021
Role based authentication for NodeJS and ExpressJS

Authentication service made for ExpressJS and MongoDB using JWT. We tried to make it as clean and structured as possible. We also provide this documentation on how to install and integrate it with your own application.

null 4 Oct 3, 2021
Building an API on nodejs with registration system, authentication, CRUD of projects and tasks.

api-token-express Building an API on nodejs with registration system, authentication, CRUD of projects and tasks. API endpoints POST { "username":

MrDiniz 4 Jan 15, 2022
Edge-side GitHub authentication

cloudflare-workers-github-auth Edge-side GitHub authentication example. Requirements node.js (v16.13.1 or later) Installation Clone this repository an

Yoshiaki Sugimoto 7 Feb 21, 2022
node.js auth package (password, facebook, & more) for Connect and Express apps

everyauth Authentication and authorization (password, facebook, & more) for your node.js Connect and Express apps. There is a NodeTuts screencast of e

Brian Noguchi 3.5k Dec 17, 2022
node.js/express module to authenticate users without password

Passwordless Passwordless is a modern node.js module for Express that allows authentication and authorization without passwords by simply sending one-

Florian Heinemann 2k Dec 14, 2022
Simple express request logger middleware for jsout.

jsout-express Simple express request logger middleware for jsout. Installation npm i jsout jsout-express -D Example Usage import {logger} from 'jsout'

Marc H. Weiner 2 Feb 25, 2022
Vue 3 + Typescript + Vite + Express

Vue 3 + Typescript + Vite + Express 目录结构

null 3 Oct 1, 2022
Express.js middleware implementation for Twitter OAuth 2.0 Client.

twitter-oauth2 Express.js middleware implementation for Twitter OAuth 2.0 Client. This module supports the following grant type available on twitter:

56 19 Dec 17, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
The authentication-server is a node app that handles user registration, authentication & authorization with JWT.

Authentication Server The authentication-server is a node app that handles user registration, authentication & authorization with JWT. Here is the REP

Oğuz Çolak 18 Jul 24, 2022
We are creating a Library that would ensure developers do not reinvent the wheel anymore as far as Authentication is concerned. Developers can easily register and download authentication codes that suits their need at any point.

#AuthWiki Resource Product Documentation Figma Database Schema First Presentation Live Link API Documentation Individual Contributions User Activity U

Zuri Training 17 Dec 2, 2022
Basic Express methood solution with mongodb and Client & Server site code example

Express with MongoDB Tutorial (Basic) React Tutorial React Inastallation React Fundamental Concepts React Advanced concepts let start Express Starter

Md. Nazmul Islam 28 Oct 28, 2022
An easy to use authentication system that can easily be built in to your Express + HBS web apps.

yoAuth An easy to use authentication system that can easily be built in to your Express + HBS web apps. Currently only supports local authentication,

null 2 Jan 21, 2022
A prebuilt Express JS Authentication & Authorization Project based on a REST API interface.

A prebuilt Express JS Authentication & Authorization Project based on a REST API interface. It has the basic authentication and Authorization routes with the latest security measures implemented so that your application is much more secure from day 1. You are welcome to build upon and extend this project as and when required.

Soumalya Bhattacharya 2 Oct 7, 2022
implements user authentication and session management using Express.js, MongoDB, and secure cookies

Auth-Flow This project is a simple user authentication system that uses Express.js and MongoDB to store user data. The system allows users to sign up

Abdelrahman Ali 4 Mar 17, 2023