Newby Coder header banner

Adding Api to NodeJs Basic Authentication Server

Adding an api in NodeJs express can be simple like declaring another route and assigning a function

Following is continuation of React Native Basic Http Authentication

Since user registration is not implemented, following example provides user data by calling another service

These calls can be replaced with something like - calls to a database

NodeJs Basic Authentication Server for Mobile applications

This has following parts:


Dependency

get-json package is used to get json data from Rest Apis

Run following command from project directory

npm install get-json --save

Project structure

No new files are added, so project structure is same as that of React Native Basic Http Authentication

Implementation

User service

getUserInfo is modified to add a service call which returns random user data

This can be changed to a custom service call or database call if implemented

User data from the external service is not stored so it can return different data on subsequent calls for a user

Another method getMockPosts is added which also makes a service call to get some data as filler for user posts

Changes made from Nodejs Basic Http Authentication are highlighted

var getJSON = require('get-json')
const users = [
  { id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User', phone: '5235234132' },
  { id: 2, username: 'ncuser', password: 'ncpassword', firstName: 'En', lastName: 'Cee', phone: '7685496767' }];

// these are accessible when this module is imported in another module as require('user_service')
module.exports = {
    authenticate,
    getUserInfo
};

async function authenticate(username, password) {
    const user = users.find(u => u.username === username && u.password === password);
    if (user) {
        const { id, ...otherUserData } = user;
        return {id: id, username: username};
    }
}

async function getUserInfo(req, res) {
  await getJSON(`https://randomuser.me/api/`, function(error, response){
    if(error != undefined || error != null) {
      res.status(400).json({ message: JSON.parse(error) });
    }
    else{
      var userdata = response.results[0];
      userdata.id = req.user.id;
      userdata.username = req.user.username;
      res.json({userdata : userdata});
    }
  });
}
 
async function getMockPosts(count, res) {
  await getJSON(`https://baconipsum.com/api/?type=meat-and-filler¶s=${count}&start-with-lorem=1`, function(error, response){
    if(error != undefined || error != null) {
      res.status(400).json({ message: JSON.parse(error) });
    }
    else{
      res.json({posts : response});
    }
  });
}

Controller

A route /initialPosts is added which is bound to getInitialPosts() methodwhich makes a service call to get 10 user posts with mock data

Additional routes also require authentication due to the authentication middleware (with no changes)

const express = require('express');
// get Router instance
const router = express.Router();
// variable to access exported methods of user_service.js
const userService = require('./user_service');

// set controller methods for routes
router.post('/authenticate', authenticate);
router.get('/getInfo', getInfo);
router.get('/initialPosts', getInitialPosts);

module.exports = router;

function authenticate(req, res, next) {
  console.log("authenticate ", req.body)
  // password is expected to be in base64 encoded form, which is decoded to send raw password to service
  var password = Buffer.from(req.body.password, 'base64').toString('ascii')
  userService.authenticate(req.body.username, password)
      // here 'user' is the object returned from authenticate() if not null, which contains 'id' of user
      .then(user => user ? res.json(user) :
          res.status(400).json({ message: 'Username or password is incorrect' }))
      // error is handled by global handler
      .catch(err => next(err));
}

function getInfo(req, res, next) {
  userService.getUserInfo(req, res)
}

// get 10 mock paragraphs as user posts
function getInitialPosts(req, res, next) {
  userService.getMockPosts(10, res);
}

Error Handler

Same as Nodejs Basic Http Authentication

Authentication Middleware

Same as Nodejs Basic Http Authentication

index.js - Server entry point

Same as Nodejs Basic Http Authentication


Run instructions

Run following command from project directory

nodejs index.js

To test running in production

sudo NODE_ENV='production' nodejs index.js

To make it as accessible over a local network such as wifi, enter local ip address with command

nodejs index.js 192.168.43.34

Here, 192.168.43.34 is ip address

Testing using html file

Save following code in a file named test.html (or some other name with .html extension) in a directory

Replace url in case server is run in some ip address other that localhost

Open the file in a browser (double-click should do that)

<!doctype html>
<html>
  <meta charset="utf-8">
  <body>
    <div>
      <div>
      <h3>Login Form</h3>
      <table>
        <tr>
          <td><label for="id_username">Enter username</label></td>
          <td><input type="text" id="id_username"></td>
        </tr>
        <tr>
          <td><label for="id_username">Enter password</label></td>
          <td><input type="password" id="id_password"></td>
        </tr>
        <tr>
          <td><button id='btn'>Authenticate</button></td>
          <td><button id='infoBtn'>Get user info</button></td>
        </tr>
      </table>
      <pre><code id="output"></code></pre>
      </div>
    </div>
  </body>
  <script>
    output = document.getElementById('output')
    function authReq() {
      output.innerHTML = ""
      username = document.getElementById('id_username').value
      password = document.getElementById('id_password').value
      const encoded =  btoa(password);
      fetch('http://127.0.0.1:4500/users/authenticate', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({username: username, password: encoded})
      })
      .then(response => response.json())
      .then((value) => {
        output.innerHTML =  JSON.stringify(value)
      });
    }
    function getInfo() {
      output.innerHTML = ""
      const encoded = 'Basic ' + btoa(username+":"+password)
      fetch('http://127.0.0.1:4500/users/getInfo', {
        method: 'GET',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'Authorization': encoded
        },
      })
      .then(response => response.json())
      .then((value) => {
        output.innerHTML =  JSON.stringify(value, null, 4)
      });
    }
    document.getElementById('btn').onclick = authReq
    document.getElementById('infoBtn').onclick = getInfo
  </script>
</html>

Test with username and password set in server

cl-nodejs-server-basic-auth-mock-data

Client Mobile Applications

Check how to connect the server with mobile applications