Руководство по аутентификации в node.js без passport.js и сторонних сервисов

Connecting Mongo to Node with Mongoose

Now that we have a database with records in it, we need a way to communicate with it from our application. We’ll be using Mongoose to achieve this. Why don’t we just use plain Mongo? Well, as the Mongoose devs like to say ,A href=”https://mongoosejs.com/docs/unstable/index.html”>on their website:

Mongoose will simply make our lives easier and our code more elegant.

Let’s go ahead and install it with the following command:

We’ll also be using passport-local-mongoose, which will simplify the integration between Mongoose and Passport for local authentication. It will add a and field to our Schema in order to store the hashed password and the salt value. This is great, as passwords should never be stored as plain text in a database.

Let’s install the package:

Now we have to configure Mongoose. Hopefully you know the drill by now: add the following code to the bottom of your file:

Here we require the previously installed packages. Then we connect to our database using and give it the path to our database. Next, we’re making use of a Schema to define our data structure. In this case, we’re creating a schema with and fields.

Finally, we add as a plugin to our Schema. This will work part of the magic we talked about earlier. Then, we create a model from that schema. The first parameter is the name of the collection in the database. The second one is the reference to our Schema, and the third one is the name we’re assigning to the collection inside Mongoose.

That’s all for the Mongoose setup. We can now move on to implementing our Passport strategy.

Simple Example of Node js Authentication with MySQL

We will authenticate user using MySQL database.We will create GET and POST type HTTP request to show login and post login information to server.I am using Bootstrap CSS to create beautiful login and registration form.

I am using following files and folder

I am creating a folder ‘nodejs_auth_example’.This is our node js project name.

views folder: This folder will contain all ejs template files.public folder: This folder will contain all external css and js files.routes folder: This folder will contain all controller file.app.php: This file will use to create nodejs application server and routes url.node_modules folder: This folder will contain all node.js packages.

Create Database and Table Structure for User Authentication

I am using MySQL server for user authentication.You need to create name database into mysql server.You can create database using GUI or from command line whatever you like, Lets create table into MySQL database using below script.

CREATE TABLE IF NOT EXISTS `users` ( `id` int(5) NOT NULL AUTO_INCREMENT, `first_name` text NOT NULL, `last_name` text NOT NULL, `mob_no` int(11) NOT NULL, `user_name` varchar(20) NOT NULL, `password` varchar(15) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf-8 AUTO_INCREMENT=4 ;

1 2 3 4 5 6 7 8 9



`first_name`text NOTNULL,

`last_name`text NOTNULL,






I am storing password as a string you can change into , I am creating this tutorial for laymen nodejs learner so haven’t use md5 or any cipher module.

Create Package.json file

We will create file for this node.js application into root path of node js application.This file define what libraries or modules will be use in this node js project.You need to add below code into file.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23







«test»»echo \»Error: no test specified\» && exit 1″

















lets install node js module using npm command, now open window and go to path of your node application, like and run below example.

Above command will install all dependency node js modules into folder.

# Advanced Auth


JWT auth scenario, for example, is different. The Strategy will produce a payload which contains data and JWT token. This information isn’t attached to the request and cannot be retrieved using the default Ts.ED decorator.

To solve it, the has two decorators and to get the argument given to the original verify function by the Strategy.

For example, the official documentation gives this javascript code to configure the strategy:


The example code can be written with Ts.ED as following:


Azure Bearer Auth

Azure bearer uses another scenario which requires to return multiple arguments. The method accepts an to return multiple values.


Discord Auth

Discord passport gives an example to refresh the token. To do that you have to create a new Strategy and register with the refresh function from module.

Here is the JavaScript code:


Ts.ED provides a way to handle the strategy built by the by using the hook.


Facebook Auth

Facebook passport gives an example to use scope on routes (permissions). We’ll see how we can configure a route with a mandatory .

Here is the corresponding Facebook protocol:



In order to use Facebook authentication, you must first create an app at Facebook Developers. When created, an app is assigned an App ID and an App Secret. Your application must also implement a redirect URL, to which Facebook will redirect users after they have approved access for your application.

The verify callback for Facebook authentication accepts , , and arguments. will contain user profile information provided by Facebook; refer to User Profile for additional information.


For security reasons, the redirection URL must reside on the same host that is registered with Facebook.

Then we have to implement routes as following:



decorator accepts a second option to configure the . It is equivalent to

The Client

The client should be quite simple. We’ll create some pages and a file. Let’s begin with the home page, or index. In your project root, create a folder called and add a file called . Add the following to it:

Here we have an empty tag where we’ll place our welcome message and, below that, a link to . The crucial part here is the tag at the bottom where we’ll handle getting the username to create the welcome message.

This is divided into four parts:

  1. We instantiate the request object using .
  2. We set the property with the function that will be called after we get our answer. In the callback, we’re checking if we got a successful response and if so, we parse the response, get the user object (the one we sent in the route, remember?), and we find the element to set its to our .
  3. We the request to the user and we set the last parameter to to make it .
  4. Finally, we the request.

Now we’ll create the login page. As before, in the HTML folder create a file called and add the following content to it:

On this page, we have a simple login form, with and fields, as well as a Submit button. Below that, we have a label where we’ll display any error messages. Remember, these are contained in the query string.

The tag at the bottom is far simpler this time. We’re instantiating a object passing the property, which contains the parameters string in our URL. Then we use the method, passing in the parameter name we’re looking for.

At this point, we either have an info message or not. So if we do, we get the element and set its to whatever that message is, and then set its property to . This will make it visible, given that by default it has a value.

Let’s set up the private page now. Again, create a file in the HTML folder with the name and add the following content:

Super simple. Just a simple message and a link which takes us back to the homepage.

That’s it for the HTML, but as you probably noticed, we’re referencing a file the tags. Let’s add that file now. Create a folder called in the root of our project and add a file to it, with the following content:

This will make our pages look decent enough. Let’s check it out!

Grab a terminal pointing to the project root and run the following command:

Now navigate to http://localhost:3000/ in your browser. You should be redirected to the login page. If you try to go to http://localhost:3000/private, it should redirect you to the login page again. There’s our route guard doing its job.

Press Ctrl + C in the terminal window to stop our server. Then head back to the file and, at the bottom of the file, add the following lines:

This uses the passport-local-mongoose method to salt the password for us. We just have to pass it in in plain text.

Now we run . The users will be created. You should comment those last lines now.

Remember the MongoDB shell terminal we left open? Go back to it and type:

This should show your three users and, as you can see, the salt and hash now occupy a good portion of the space on the terminal.

That’s all we need for the app to work. We’re done!

Head back to the browser, try to log in with one of the credentials we entered and you’ll see the login message with the given username in it.

Фундамент OAuth

    Есть замечательный цикл статей про OAuth: Beginner’s Guide to OAuth (на английском; от автора с говорящим прозвищем hueniverse). Его изучение отнимет у вас приблизительно 4 часа, если вы до этого момента совершенно не знакомы с темой.

Приложение = Consumer + доступ к API


  • Скрипт формы импорта контактов из GMail (см. пример выше).
  • Приложение для iPhone, позволяющее писать сообщения в Twitter.
  • Прямоугольный виджет на вашем сайте, в котором отображаются последние сообщения чата и есть возможность написать новое.

Token = Key + Secret

Сообщение = Документ + Цифровая подпись

Цифровая подпись не шифрует документ, она лишь гарантирует его подлинность!

  1. Consumer добавляет цифровую подпись к сообщению, в общем виде —
    $transfer = $message . "-" . md5($message . $sharedSecret);
    // $transfer = "Мой телефон 1234567" . "-" . md5("Мой телефон 1234567" . "529AeGWg")
  2. Service Provider принимает данные, разбивает их обратно на 2 части — $message и $signature — и проделывает точно такую же операцию:
    $signatureToMatch = md5($message . $sharedSecret);
    // $signatureToMatch = md5("Мой телефон 1234567" . "529AeGWg");
    Дальше остается только сравнить получившееся значение $signatureToMatch с тем, что было в полученных данных $signature и рапортовать о подделке, если значения не совпали.
    Итак, чтобы сформировать MD5-подпись, обязательно знать Shared Secret. (Кстати, кроме MD5 есть и другие алгоритмы необратимого хэширования.) Злоумышленник не знает Shared Secret, поэтому и подпись он подделать не может.

5.2. Сессии в Express¶

В основе сессий в Express лежит соответствующий средний слой (middleware) из Connect, который, в свою очередь, опирается на механизм хранения данных. Существует хранилище в памяти, а так же сторонние хранилища, включая connect-redis и connect-mongodb. В качестве альтернативы так же можно рассматривать cookie-sessions, который хранит данные сессии в пользовательской куке (cookie).

Поддержка сессий может быть включена следующим образом:


Размещение этого кода в разделе конфигурации приложения очень важно. В случае ошибки сессионная переменная не появится в объекте запроса

Я разместил этот кусок между и . Полную версию кода вы можете посмотреть на GitHub.

Теперь в HTTP-обработчиках будет доступна переменная :

Step 2: Install Dependencies

The following packages will be used:

  • express, a minimal and flexible Node.js web application framework
  • bcrypt, A library to help you hash passwords.
  • jsonwebtoken, An implementation of JSON Web Tokens.
  • mongoose, Mongoose provides a straight-forward, schema-based solution to model your application data.
  • passport, an authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped into any Express-based web application.
  • passport-jwt, A Passport strategy for authenticating with a JSON Web Token.
  • cors, CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
  • dotenv, Dotenv is a zero-dependency module that loads environment variables from a file into .
  • express-validator, express-validator is a set of express.js middlewares that wraps validator.js validator and sanitizer functions.
$ npm install bcrypt express jsonwebtoken mongoose passport passport-jwt cors dotenv express-validator --save

Image Upload Dependencies

  • multer: Node.js middleware for handling `multipart/form-data`.
  • datauri, Node.js and CLI to generate Data URI scheme.
  • cloudinary
$ npm install multer datauri cloudinary --save
  • jade, a templating engine, primarily used for server-side templating in NodeJS.
  • @sendgrid/mail, This is a dedicated service for interaction with the mail endpoint of the Sendgrid v3 API
npm install jade @sendgrid/mail --save

Development Dependencies

nodemon: nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.

$ npm install nodemon --save-dev----# add the following to package.json scripts section"scripts": {"start": "nodemon src/server.js"},


Давайте проанализируем наше приложение. Что нужно, чтобы его реализовать:

У нас — онлайн веб-приложение, поэтому нам нужен HTTP-сервер; Нашему серверу необходимо обслуживать различные запросы в зависимости от URL, по которому был сделан запрос. Для этого нам нужен какой-нибудь роутер (маршрутизатор), чтобы иметь возможность направлять запросы определенным обработчикам; Для выполнения запросов, пришедших на сервер и направляемые роутером, нам нужны действующие обработчики запросов; Роутер, вероятно, должен иметь дело с разными входящими POST-данными и передавать их обработчикам запросов в удобной форме

Для этого нам нужен какой-нибудь обработчик входных данных; Мы хотим не только обрабатывать запросы, но и показывать пользователю контент по запрошенным URL-адресам, поэтому нам нужна некая логика отображения для обработчиков запросов, чтобы иметь возможность отправлять контент пользовательскому браузеру; Последнее, но не менее важное — пользователь сможет загружать картинки, поэтому нам нужен какой-нибудь обработчик загрузки, который возьмёт на себя заботу о деталях.

Давайте подумаем о том, как бы мы реализовали это на PHP. Скорее всего, типичное решение будет на HTTP-сервере Apache с установленным mod_php5.

Это относится к первому пункту наших задач, то есть, «принимать HTTP-запросы и отправлять готовые веб-странички пользователю» — вещи, которые PHP сам не делает.

С Node.js — немного иначе. Потому что в Node.js мы не только создаем наше приложение, мы также реализуем полноценный HTTP-сервер. Действительно, наше веб-приложение и веб-сервер — в сущности, одно и тоже.

Может показаться, что это приведет к лишней работе, но сейчас вы увидите, что с Node.js это не так.

Давайте просто начнём реализовывать нашу первую задачу — HTTP-сервер.


To follow along with this tutorial, you’ll need to have Node and MongoDB installed on your machine.

You can install Node by heading to the official Node download page and grabbing the correct binaries for your system. Alternatively, you can use a version manager — a program that allows you to install multiple versions of Node and switch between them at will. If you fancy going this route, please consult our quick tip, “Install Multiple Versions of Node.js Using nvm”.

MongoDB comes in various editions. The one we’re interested in is the MongoDB Community Edition.

The project’s home page has excellent documentation and I won’t try to replicate that here. Rather, I’ll offer you links to instructions for each of the main operating systems:

  • Install MongoDB Community Edition on Windows
  • Install MongoDB Community Edition on macOS
  • Install MongoDB Community Edition on Ubuntu

If you use a non-Ubuntu–based version of Linux, you can check out for installation instructions for other distros. MongoDB is also normally available through the official Linux software channels, but sometimes this will pull in an outdated version.

Note: You don’t need to enter your name and address to download MongoDB. If prompted, you can normally dismiss the dialog.

If you’d like a quick refresher on using MongoDB, check out our beginner’s guide, “An Introduction to MongoDB”.

With ExpressJS and PassportJS

It is easy to get confused on authentication and authorization. While authentication verifies the user’s identity, authorization verifies that the user in question has the correct permissions and rights to access the requested resource. The two always work together. Authentication occurs first, then authorization.

  1. In your Passport login strategy, when the user identification is verified, roll-in its authorization profiles:

    passport.use(newLocalStrategy(function(username,password,done){User.findOne({ username username },function(err,user){if(err){returndone(err);}if(!user){returndone(null,false);}if(!user.verifyPassword(password)){returndone(null,false);}...user.authProfile=compileProfile(rawProfiles);returndone(null, user);});}));
  2. In the passport «serializeUser» function, save the compiled profile to the session storage:

    passport.serializeUser(function(identity,done){done(null, identity);});
  3. In the passport «deserializeUser» function, initialize the Authorization object with the session profile:

    passport.deserializeUser(function(identity,done){constuser={    identity identity,    Authorizationnull};if(identity.userid&&identity.profile)user.Authorization=newAuthorization(identity.userid,identity.profile);done(null, user);});
  4. In your restful APIs, embed the authorization checks:

    addBlogfunction(req,res){if(!req.user.Authorization.check('blog',{Tagreq.body.blog.tag,IDreq.body.blog.ID, Action'Add'})){res.end('You do not have the permission to add a new blog!');}elseblog.addBlog(req.body.blog,function(msg,blogId){...res.json(msg);})}

When a user is logged on, the authorization profiles are compiled and saved in the login session storage. Then each time the user performs an action on an object, corresponding authorization checks can be done before it actually happens. Developers can decide where to embed the «authorization.check()» statements.

Шаг 2

Пока что мы свободно можем ходить по всем страницам, включая страницу админки. Как же мы ограничим к ней доступ? Каков вообще будет алгоритм? Мы будем делать следующее: в самом начале страницы мы будем проверять, есть ли нужная нам метка в сессии или, проще говоря, существует ли определенная сессионная переменная (также можно проверять равно ли значение сессионной переменной определенному значению). Если такой переменной нет, значит пользователь, запрашивающий эту страницу, не авторизован, а значит мы осуществим его редирект на страницу авторизации, где ему будет предложено заполнить форму с именем и паролем. Алгоритм предельно прост — реализуем его. Переходим к файлу admin.php, открываем в самом верху конструкцию PHP и напишем такой код:

<?php session_start();

if(!$_SESSION){ header(«Location: enter.php»); exit; } ?>

1 2 3 4 5 6 7 8




header(«Location: enter.php»);


} ?>

Давайте теперь прочитаем это код. Во-первых, мы открыли сессию, как Вы помните — это обязательное условие при работе с сессиями. Далее, мы создали простое условие, которое можно прочитать так: «если в массиве $_SESSION не существует элемента admin — будем выполнять блок действий, заключенный в операторные скобки». А в блоке кода мы при помощи функции header() производим редирект пользователя на страницу enter.php (это страница авторизации). После функции header() обязательно завершаем выполнение скрипта при помощи функции exit(). Если же условие не выполнится, т.е., в массиве $_SESSION будет элемент admin — это значит, что пользователь уже успешно авторизован, и мы пропустим блок действия в операторных скобках, т.е., никакого редиректа происходить не будет, и мы покажем запрошенную страницу.

Шаг 4

Далее нам нужно написать на странице с формой ее обработчик, который будет принимать данные из формы и сравнивать, совпадают ли логин и пароль из формы с теми, которые есть у нас. Для этого откроем вверху страницы авторизации конструкцию PHP и начнем писать код. Для начала мы должны открыть сессию — ведь именно здесь мы будем создавать метку в сессии, если получены верные логин и пароль. На этой же странице мы будем хранить логин и пароль администратора. Обычно эти данные хранятся в базе данных (БД), но у нас будет только 1 пользователь (администратор), а потому хранить его данные для входа в БД не совсем рационально. Если же пользователей будет не один, т.е., мы, к примеру, пишем проект, в котором имеется регистрация, то, конечно же, без БД в таком случае обойтись будет сложно.

Итак, наш логин будет «admin» и хранить мы его будем в переменной $admin. Пароль будет «mypass» и он будет храниться в переменной $pass. Но хранить пароли в открытом виде не принято — это противоречит принципам безопасности. Хранить пароль мы будем в зашифрованном виде, а зашифровать его нам поможет функция md5(). Эта функция шифрует строку по специальному алгоритму, и на выходе мы получаем строку из 32 символов (ее называют хеш). Если мы зашифруем строку «mypass» (это можно сделать, например, в файле contact.php):

<?php echo md5(‘mypass’); ?>

1 2 3




то на выходе получим строку «a029d0df84eb5549c641e04a9ef389e5″ — это и будет наш зашифрованный пароль. Пока что код страницы авторизации будет таким:

<?php session_start();

$admin = ‘admin’; $pass = ‘a029d0df84eb5549c641e04a9ef389e5’; ?> <p><a href=»index.php»>Главная</a> | <a href=»contact.php»>Контакты</a> | <a href=»admin.php»>Админка</a></p> <hr /> Это страница авторизации. <br /> <form method=»post»> Username: <input type=»text» name=»user» /><br /> Password: <input type=»password» name=»pass» /><br /> <input type=»submit» name=»submit» value=»Войти» /> </form>

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15










<form method=»post»>

Username<input type=»text»name=»user»><br>

Password<input type=»password»name=»pass»><br>

<input type=»submit»name=»submit»value=»Войти»>


Бесплатный курс по PHP программированию

Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC

В курсе 39 уроков | 15 часов видео | исходники для каждого урока

Получить курс сейчас!

Step 11: Create Server

Update the file.


Run the command below to start the server

npm start<< - OUTPUTServer running on http://localhost:3000/MongoDB --  database connection established successfully!>>


Use Postman to test.

User IndexTry accessing the user index.

Register and LoginCreate a POST request to .Create a POST request to .

Update User Info and Upload Profile ImageTry updating the user information and uploading a profile image using endpointpassing the token.

Login and Recover PasswordLogin with your current password.Create a POST request to .

Login and Password Recovery

Reset Password and Login with new PasswordReset the password then attempt to login with your old password. This should fail. Login with your new password.

Reset Password and Login

Related Tutorials

  1. Node.js API: Add CRUD Operations With Pagination, Filtering, Grouping, and Sorting Capabilities.
  2. Tutorial 4: How to Build a Laravel 5.4 JWT-Powered Mobile App Authentication API
  3. Tutorial 5: How to Build a Laravel 5.4 JWT Authentication API with E-Mail Verification
  4. Tutorial 6 & 7: How to Build a Laravel 5.4 Administration Module with Role-based permissions using Entrust package


Authorization Object usually corresponds to a business object, like «user», «blog», «material», «order», and so on. Sometimes, it can also be an abstract object that is only for the permission check purposes. For example, if you want to show the total blog reads to certain users, then you need to create an authorization object like «blogStatistic».

An authorization object can be assigned with more than one Authorization Fields. Usually, we have the «Action» authorization field to indicates the operations allowed to a business object. Besides, we can have attributes derived from the business object as authorization fields. This is to facility the permission management by easily differentiate object instances through attributes. For example, it is very common to use organizational attributes as authorization fields, such as «company», «department», and «group» on the «user» object.

Authorization describes permissions on a business object. It is an instance of an authorization object with concrete authorization values on each authorization field. Below example shows an authorization of the «user» authorization object. It allows the granted identity has the permission to «Create», «Edit», «Display», «Lock», and «Unlock» users that belong to the «Ordinary» group.


Note: authorizations on the same authorization object won’t be merged as one when doing authorization checks. Each authorization is an independent permission description. They are examined separately during authorization checks.

For example, if below authorization is assigned to an identity together with the above authorization. It doesn’t mean the identity can do «Edit», «Lock», and «Unlock» operations on users that belong to the «Admin» user groups.


Authorization Profile consists of multiple authorizations. It is a logic representation of authorizations that can be assigned to an identity as a unit. Here is an authorization profile which consists of 2 authorizations:


Note: «raw profile» and «compiled profile» are differentiated by different perspectives. When the authorization profiles are maintained by the administrator, they are called raw profiles. When the system do authorization checks, the raw profiles must be converted to a compiled profile. This is mainly to achieve better performance by sorting and grouping authorizations.

Implementing Local Authentication

And finally, this is what we came here to do! Let’s set up the local authentication. As you’ll see below, we’ll just write the code that will set it up for us:

There’s quite some magic going on here. First, we make use the local strategy by calling on our model — courtesy of — which takes care of everything so that we don’t have to set up the strategy. Pretty handy.

Then we’re using and callbacks. The first one will be invoked on authentication, and its job is to serialize the user instance with the information we pass on to it and store it in the session via a cookie. The second one will be invoked every subsequent request to deserialize the instance, providing it the unique cookie identifier as a “credential”. You can read more about that in the .

5.3. Сессии в MongoDB¶

Для поддержки сессий в MongoDB необходимо установить connect-mongodb:

npm install connect-mongodb

Работает connect-mongodb так же как и любое другое хранилище сессий. Во время настройки приложения необходимо указать детали соединения:

app.configure('development', function() {
  app.set('db-uri', 'mongodb://localhost/nodepad-development');

var db = mongoose.connect(app.set('db-uri'));

function mongoStoreConnectionArgs() {
  return { dbname db.db.databaseName,
           host db.db.serverConfig.host,
           port db.db.serverConfig.port,
           username db.uri.username,
           password db.uri.password };

  store mongoStore(mongoStoreConnectionArgs())

Большая часть этого кода не понадобилась бы, если бы авторы API реализовали стандартный формат настроек соединения. Я написал функцию, извлекающую настройки соединения из Mongoose. В этом примере, переменная хранит экземпляр соединения Mongoose, который ждет настроек соединения в виде URI. Этот формат, кстати, мне более всего симпатичен из-за своей простоты и легкости для запоминания. Строку соединения я сохраняю с помощью .

При работе с Express бывает полезно использовать . Так же следует запомнить, что для доступа к настройке следует использовать , а не .

Starting frontend and backend simultaneously

We have validated that our backend works and that it allows us to register and log users in. Let’s hook that up with our frontend. Right now we have a and a folder and we would have to start our frontend and backend separately via:

  • Frontend: Navigate to the folder and run
  • Backend: Navigate to the folder and run

Let’s simplify this, such that we can start both in unison. First, we have to initialize our project folder as an npm project. Then we to add concurrently as a dev dependency.

yarn add concurrently --dev

Additionally, we have to add a script to our (in the project root folder) to start our backend and frontend simultaneously. Your should look something like this now:

To download check out this

Now, if we run in our project root-folder, both the backend and the frontend will get booted up.

С этим читают