Node Basic authentication and access control

Using Passport to protect endpoints

Node Basic authentication and access control

by John Vincent

Posted on April 21, 2017

Build app to demonstrate basic authentication.

From Thinkful course Node 3.3.1.

Final Result

My Git repository

Getting Started

Clone repository

cd MyDevelopment/github-clones

git clone

Create Github repository node-basic-auth

Copy source files from:




Commit to repository

cd MyDevelopment/github/thinkful
create-repo node-basic-auth

Install dependencies

cd node-basic-auth
npm install

Start app

npm start

Test App Using Postman

List users

GET localhost:8080/users

return no records.

Add a User:

POST localhost:8080/users
    key: content-type
    value: application/json
Body: raw

    "username": "foo",
    "password": "password",
    "firstName": "foo"

Record is created

status: 201
  "username": "foo",
  "firstName": "foo",
  "lastName": ""

Query from database shows record has been created.

List users

GET localhost:8080/users

Access Control

Endpoint with access control

GET localhost:8080/users/me


status: 401 Unauthorized
content: Unauthorized

WWW-Authenticate →Basic realm="Users"

To authenticate, we need to use the "basic" strategy at realm "Users".

Add Authorization Header


GET localhost:8080/users/me
Authorization: Basic Auth

Username: foo
Password: password

Update Request which creates a Header.

Send now returns:

status: 200
  "user": {
    "username": "foo",
    "firstName": "foo",
    "lastName": ""

Encrypting Passwords


UserSchema.methods.validatePassword = function(password) {
    return, this.password);

UserSchema.statics.hashPassword = function(password) {
    return bcrypt.hash(password, 10);

Data validation in router.js'/', (req, res) => {
    if (!req.body) {
        return res.status(400).json({message: 'No request body'});

    if (!('username' in req.body)) {
        return res.status(422).json({message: 'Missing field: username'});

    let {username, password, firstName, lastName} = req.body;

    if (typeof username !== 'string') {
        return res.status(422).json({message: 'Incorrect field type: username'});

    username = username.trim();

    if (username === '') {
        return res.status(422).json({message: 'Incorrect field length: username'});

    if (!(password)) {
        return res.status(422).json({message: 'Missing field: password'});

    if (typeof password !== 'string') {
        return res.status(422).json({message: 'Incorrect field type: password'});

    password = password.trim();

    if (password === '') {
        return res.status(422).json({message: 'Incorrect field length: password'});

    // check for existing user
    return User.find({username})
        .then(count => {
            if (count > 0) {
                return res.status(422).json({message: 'username already taken'});
            // if no existing user, hash password
            return User.hashPassword(password);
        .then(hash => {
            return User
                    username: username,
                    password: hash,
                    firstName: firstName,
                    lastName: lastName
        .then(user => {
            return res.status(201).json(user.apiRepr());
        .catch(err => {
            res.status(500).json({message: 'Internal server error'});

Protecting Endpoints with Passport


const passport = require('passport');


const basicStrategy = new BasicStrategy((username, password, callback) => {
    let user;
    User.findOne({username: username})
        .then(_user => {
            user = _user;
            if (!user) {
                return callback(null, false, {message: 'Incorrect username'});
            return user.validatePassword(password);
        .then(isValid => {
            if (!isValid) {
                return callback(null, false, {message: 'Incorrect password'});
            } else {
                return callback(null, user);


Protect endpoint

    passport.authenticate('basic', {session: false}), (req, res) => res.json({
        user: req.user.apiRepr()


session: true
    authenticate once to make successive requests.

session: false
    supply credentials on each request.