Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Build and Authenticate a NodeJS App With JSON Web Tokens: Part II

DZone's Guide to

Build and Authenticate a NodeJS App With JSON Web Tokens: Part II

In Part II, we continue by building polls and the UI, and wire up our views and controllers.

· Web Dev Zone
Free Resource

Never build auth again! Okta makes it simple to implement authentication, authorization, MFA and more in minutes. Try the free developer API today! 

Did you miss out on Part I? Check it out here!

Building Awesome Polls

Let's write some NodeJS code. The first piece of functionality that we will implement is our main entry point into the application. Open up the app.js file, or create it if you haven't already. For now, let's add the following:

// We saw how we could download dependencies via npm. To use those dependencies in our code we require them. The syntax to require a library is the keyword require and a string for the name of the library. We assign this require function to a variable and can then access methods from the library through that variable. Here we are requiring all of our dependencies at the top of the page as is good practice.
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var dotenv = require('dotenv');

// We are using the dotenv library to load our environmental variables from the .env file. We don't have anything in the .env file for now, but we will soon.
dotenv.load();

// Just like external libraries, we can import our application code using the require function. The major difference is that we have to give the exact path to our file. We saw in the directory structure section that we will have an index.js file in a routes directory. Go ahead and create it if you haven't already, otherwise you'll get errors when compiling the code.
var routes = require('./routes/index');

// This line of code instantiates the Express JS framework. We assign it to a variable called app, and will add our configruation to this variable.
var app = express();

// The .set method allows us to configure various options with the Express framework. Here we are setting our views directory as well as telling Express that our templating engine will be Jade. More on that soon.
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// The .use method is similar to the .set method, where it allows us to set further configurations. The .use method also acts as a chain of events that will take place once a request hits our Node Js application. First we'll log the request data, parse any incoming data, and so on.
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
  // Here we are creating a unique session identifier
  secret: 'shhhhhhhhh',
  resave: true,
  saveUninitialized: true
}));
app.use(express.static(path.join(__dirname, 'public')));

// catch 404 and forward to error handler.
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// If our applicatione encounters an error, we'll display the error and stacktrace accordingly.
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.send(err);
});

// Finally, we'll choose to have our app listen on port 3000. This means that once we launch our app, we'll be able to navigate to localhost:3000 and see our app in action. You are free to choose any port you want, so 8080, or 80, or really any number will work. The reason 3000 is typically used is because it's the lowest port number that can be used without requiring elevated privileges on Mac/Linux systems.
app.listen(3000);


Let's test our app so far. To run our app, we'll simply run the command node app in your terminal. Next, navigate to locahost:3000 in your web browser. If all went as expected, you should just see a 404 page not found error. That is the expected behavior since we did not add any routes to our application, but we did add a page not found error handler. Next, let's add some routes.

Express.js Routing

If you followed along with our directory structure, you'll have created an index.js file in a directory titled routes. If you haven't already done so, go ahead and create this file, and open it. We will define our application routes here. To accomplish this, we'll write the following:

// Again we are importing the libraries we are going to use
var express = require('express');
var router = express.Router();

// On our router variable, we'll be able to include various methods. For our app we'll only make use of GET requests, so the method router.get will handle that interaction. This method takes a string as its first parameter and that is the url path, so for the first route we are just giving it '/', which means the default route. Next we are defining a Node Js callback function, that takes three parameters, a request (req), a response (res), and an optional next (next) parameter. Finally, in our callback function, we are just send the message "You are on the homepage".
router.get('/', function(req, res, next) {
  res.send('You are on the homepage');
});

// We are going to do the same thing for the remaining routes.
router.get('/login',function(req, res){
  res.send('You are on the login page');
});

router.get('/logout', function(req, res){
  res.send('You are on the logout page');
});

router.get('/polls', function(req, res){
  res.send('You are on the polls page');
})

router.get('/user', function(req, res, next) {
  res.send('You are on the user page');
});

// Finally, we export this module so that we can import it in our app.js file and gain access to the routes we defined.
module.exports = router;


Before moving on, let me briefly explain how routing in Express works. When we define a route, say our /user route, and pass the callback function, we are telling Express that when the browser points to localhost:3000/user, the specified callback function will be called.

The req parameter will have all the details of the request such as the IP address, parameters passed with the route, and even items we attach to it through Express middleware.

The res parameter handles our response from the server to the browser. Here we can return a view, an error, JSON data, and so on. Finally, we can optionally add a next parameter.

Calling next will exit the current function and move down the middleware stack. The way requests are processed in Express.js is that they go through a stack of functions. At the end of each function, you can either call next to go the next function in the stack, or call res and send a response to the browser. Once an appropriate res method has been called, the execution of that request is stopped. Middleware is a great way to separate our code into logical pieces. For example, we can have middleware that transforms our request or checks to see if a user is logged in before continuing. We'll see how to do that in the next section.

Let's get back to our routes. We have defined them, but if we run our application and try to access localhost:3000/login for example, we'll still see the 404 error. We haven't linked our routes to our app. Let's do that next. Open the app.js file and we'll make the following changes.

// We have commented out the existing code so that you can see where to add the new code.

//DO NOT COMMENT OUT ANYTHING IN YOUR FILE

// var express = require('express');
// var path = require('path');
// var logger = require('morgan');
// var cookieParser = require('cookie-parser');
// var bodyParser = require('body-parser');
// var session = require('express-session');
// var dotenv = require('dotenv');

// dotenv.load();

// Just like external libraries, we can import our application code using the require function. The major difference is, we have to give the exact path to our file. We saw in the directory structure section that we will have an index.js file in a routes directory. Go ahead and create it if you haven't already, otherwise you'll get errors when compiling the code.
var routes = require('./routes/index');

// var app = express();

// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'jade');

// app.use(logger('dev'));
// app.use(bodyParser.json());
// app.use(bodyParser.urlencoded({ extended: false }));
// app.use(cookieParser());
// app.use(session({
//  secret: 'shhhhhhhhh',
//  resave: true,
//  saveUninitialized: true
// }));
// app.use(express.static(path.join(__dirname, 'public')));

// Here we are going to use add our routes in a use statement which will link the routes we defined to our app.
app.use('/', routes);

// app.use(function(req, res, next) {
//  var err = new Error('Not Found');
//  err.status = 404;
//  next(err);
// });

// app.use(function(err, req, res, next) {
//  res.status(err.status || 500);
//  res.render('error', {
//    message: err.message,
//    error: err
//  });
// });

// app.listen(3000);


With this change saved, restart your Node server and now navigate to localhost:3000/users and you should just see the text "Your are on the users page" displayed. If we go to a route that we haven't defined like localhost:3000/yo, we'll get the 404 page like we'd expect. Alright, so far so good. We have our routes working, next let's go ahead and build our UI views.

Building the UI

Next, let's build our views. NodeJS and Express are very extensible and we have a lot of choices and options when choosing a templating engine for our application. In this tutorial we will use Jade (recently renamed to Pug). Jade is perhaps one of the oldest view engines, but other options such as EJS, Mustache, Dust, and so on exist. In our app.js file, we already declared that our view engine is going to be Jade, and that our views will be stored in a directory titled views. In this tutorial, we won't go over the Jade/Pug syntax, so if you are unfamiliar, please check out the official tutorial.

We are going to build five unique views. Jade/Pug allows us to extend one layout and build on top of it, so we are going to do that in this simple application. Let's create a file named layout.jade. Our views will extend this layout and add on their unique properties. The contents of this file will be as follows:

doctype html
html
  head
    meta(charset="utf-8")
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css", rel="stylesheet")
    link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css')
    script(src="https://cdn.auth0.com/js/lock/10.3/lock.min.js")
  body
    block content


Next, let's build our homepage. Our homepage will just display the name of our app and present the user a link to log in. Create a file called index.jade and paste in the following:

extends layout

block content  
  h1 
    i.fa.fa-lg.fa-pie-chart 
    span Awesome Polls
  h2 Welcome to the Awesome Polls Administrator website.
  p To access the polls, please login.
  br
  a(href="/login")
    button() Login


Awesome Polls Homepage

For our next page, let's build the user details page. This is where we'll display the logged in user's information. Create a user.jade file and the implementation is as follows:

extends layout

block content
  img(src="#{user.picture}")
  h2 Welcome #{user.nickname}!
  br
  a(href='/logout') Logout


Awesome Polls User Details Page

With the users page done, next, let's build the polls page. Create a file called polls.jade.

extends layout

block content  
  div.clearfix
    div.pull-left
      i.fa.fa-lg.fa-pie-chart
      span Awesome Polls
    div.pull-right
      img(src="#{user.picture}", style="height:24px; border-radius: 30px;")  
      strong(style="margin: 0px 10px;") #{user.nickname} 
      a(href="/logout") Logout
  br
  div.jumbotron
    h1.text-center 2016 Presidential Election
  each poll, index in polls
    if (poll.estimates.length > 0)
      div.col-sm-4
        div(class="panel panel-default", style="min-height: 150px;")
          div.panel-title
            div.panel-heading=poll.short_title
          div(class="panel-body", style="min-height: 100px;")
            ul.list-unstyled
              each person, index in poll.estimates
                li
                  if index == 0
                    p
                      strong #{person.choice}
                    div.progress
                      div(class="progress-bar progress-bar-success", style="width: #{person.value}%", role="progressbar")
                        span=person.value
                  else
                    p
                      span #{person.choice}
                    div.progress
                      div(class="progress-bar progress-bar-info", style="width: #{person.value}%", role="progressbar")
                        span=person.value
          div.panel-footer
            a.btn.btn-sm View Results  
            a.btn.btn-sm.write-report Write Report


Awesome Polls Details Page

Next, let's pretty up our error page. We'll create a file called error.jade and paste the following code:

extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack}


Awesome Polls Error Page

Lastly, we'll also create a stub for our login page by creating a file called login.jade, but we'll leave it blank for now.

Wiring up our Views and Controllers

Finally, we are ready to wire up our views and controllers with actual functionality. Remember, we are storing our controllers in the routes/index.js file. Let's open up that file and make the following adjustments:

var express = require('express');
var passport = require('passport');
var router = express.Router();
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn();
var request = require('request');

// We are going to want to share some data between our server and UI, so we'll be sure to pass that data in an env variable.
var env = {
};

router.get('/', function(req, res, next) {
  // Now, rather then just sending the text "You are on the homepage", we are going to actually render the view we created using the res.render method. The second argument will allow us to pass in data from the backend to our view dynamically.
  res.render('index', { env: env });
});

router.get('/login',function(req, res){
  // Same thing for the login page.
  res.render('login', { env: env });
});

router.get('/logout', function(req, res){
  // For the logout page, we don't need to render a page, we just want the user to be logged out when they hit this page. We'll use the ExpressJS built in logout method, and then we'll redirect the user back to the homepage.
  req.logout();
  res.redirect('/');
});

router.get('/polls', ensureLoggedIn, function(req, res){
  // You may have noticed that we included two new require files, one of them being request. Request allows us to easily make HTTP requests. In our instance here, we are using the Huffington Post's API to pull the latest election results, and then we're sending that data to our polls view.
  // The second require was the connect-ensure-loggedin library, and from here we just required a method called ensureLoggedIn, which will check and see if the current user is logged in before rendering the page. If they are not, they will be redirected to the login page. We are doing this in a middleware pattern, we first call the ensureLoggedIn method, wait for the result of that action, and finally execute our /polls controller.
  request('http://elections.huffingtonpost.com/pollster/api/charts.json?topic=2016-president', function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var polls = JSON.parse(body);
      // For this view, we are not only sending our environmental information, but the polls and user information as well.
      res.render('polls', {env: env, user: req.user, polls: polls});
    } else {
      res.render('error');
    }
  })
})

router.get('/user', ensureLoggedIn, function(req, res, next) {
  // Same thing for our 
  res.render('user', { env: env, user: req.user });
});

module.exports = router;


This completes our controller's implementation. We did a lot in this section. We saw how we could send data between our server and front end, how to use the excellent NodeJS request library to make calls to an external API, and also how to secure our routes and prevent unauthorized access. We haven't built the user authentication system just yet, we'll do that next.

Before we close out this section, let's make one quick change to our app.js file. If you recall, in our app.js file we built our error handler. In the last section, we created a pretty view for our errors, so let's make sure we're using that view.

app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  //res.send(err)
  res.render('error', {
    message: err.message,
    error: err
  });
});

Keep an eye out for the final part to this series, coming soon!

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
node js ,web dev ,app ,json

Published at DZone with permission of Ado Kukic, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}