Categories
Node.js Basics

Node.js Basics — Debugging Apps

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Logging with Morgan

To let us debug our Node.js apps easily, we can use the morgan package to add a logger into our app.

To install it, we run:

npm i morgan

Then we can use it by writing:

const Morgan = require('morgan'),
  Router = require('router'),
  http = require('http');
router = new Router();
router.use(Morgan('tiny'));

http.createServer(function(request, response) {
  router(request, response, function(error) {
    if (!error) {
      response.writeHead(404);
    } else {
      console.log(error.message, error.stack);
      response.writeHead(400);
    }
    response.end('n');
  });
}).listen(8000);

We add the Morgan middleware into our router by calling the router.use method with the Morgan('tiny') middleware.

Now we see logging in our app.

Now we can remove the console.log and write:

const Morgan = require('morgan'),
  Router = require('router'),
  http = require('http');
router = new Router();
router.use(Morgan('tiny'));

http.createServer(function(request, response) {
  router(request, response, function(error) {
    let info = process.versions;
    info = JSON.stringify(info);
    response.writeHead(200, {
      'Content-Type': 'application/json'
    });
    response.end(info);

  });
}).listen(8000);

and still get logging.

Alternatively, we can use the bunyan package to do the logging.

To install it, we run:

npm i bunyan

Then we can use it by writing:

const Bunyan = require('bunyan');
const logger = Bunyan.createLogger({
  name: 'example'
});
logger.info('Hello logging');

We require the bunyan package. Then we create our logger with the createLogger method.

The name is the name of the logger.

Then we use the logger.info method to log anything we want.

We can log items with other levels of logging by using various methods.

For example, we can write:

const Bunyan = require('bunyan');
const logger = Bunyan.createLogger({
  name: 'example'
});
logger.info('Hello logging');
logger.trace('Trace');
logger.debug('Debug');
logger.info('Info');
logger.warn('Warn');
logger.error('Error');
logger.fatal('Fatal');

Then we get object with various values of the level property logged to let us know the severity level of the log item.

We can also write:

const Bunyan = require('bunyan');
const logger = Bunyan.createLogger({
  name: 'example',
  level: Bunyan.TRACE

});
logger.info('Hello logging');
logger.trace('Trace');
logger.debug('Debug');
logger.info('Info');
logger.warn('Warn');
logger.error('Error');
logger.fatal('Fatal');

to set the level in when we call createLogger .

With Bunyan, we can also write the logged data to a file.

To do that, we write:

const Bunyan = require('bunyan');
const logger = Bunyan.createLogger({
  name: 'example',
  streams: [{
      level: Bunyan.INFO,
      path: './log.log'
    },
    {
      level: Bunyan.INFO,
      stream: process.stdout
    }
  ]
});
logger.info('Hello logging');
logger.trace('Trace');
logger.debug('Debug');
logger.info('Info');
logger.warn('Warn');
logger.error('Error');
logger.fatal('Fatal');

We add the streams property to add objects to specify where the log data goes.

The first entry of the streams array has the path property to specify the location to write to.

The 2nd object specifies that we write to stdout, which means we print the items on the screen.

Conclusion

We can add logging with various loggers.

We can use Morgan or Bunyan to add logging capabilities to our Node.js apps.

Categories
Node.js Basics

Node.js Basics — Add Authentication to an Express App with jsonwebtoken

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Bearer Token Authentication

We can generate a token to identify authenticated users.

When they want to make requests to our server, they send in the auth token to our server to decode it.

If it’s decoded successfully, then we let the user make the request.

We can install the jsonwebtoken package by running:

npm i jsonwebtoken

Then we can use it by writing:

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');

const users = {
  foo: {
    username: 'foo',
    password: 'bar',
    id: 1
  },
  bar: {
    username: 'bar',
    password: 'foo',
    id: 2
  }
}

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(express.static('public'));
app.get('/', (req, res) => {
  res.sendFile('public/index.html');
});

app.post(
  '/login',
  function(req, res) {
    const {
      username,
      password
    } = req.body;
    const user = users[username];
    if (user === undefined) {
      return res.status(401).send('invalid user')
    }
    if (user.password !== password) {
      return res.status(401).send('invalid password')
    }

    const {
      id
    } = user;
    jwt.sign({
      id,
      username
    }, 'shhhhh', function(err, token) {
      res.send(token);
    });
  }
);

app.listen(3000, () => console.log('server started'));

In the /login route, we get the username and password properties that we make a request within the JSON request body.

Then we check the user in the users object.

If the username or password is invalid, then we send the status 401 with a message indicating the error.

Once everything is valid, then we create the token with the jwt.sign method.

The first argument is the data that will be in the token.

Then 2nd is the secret that we sign the token with.

The last argument is the callback that’s run when the token is created.

Then we send the token back to the client.

So if we make a POST request with the /login route and the following request body:

{
    "username": "foo",
    "password": "a"
}

We get 'invalid password' return with the 401 status.

If we make the same request with a valid body like:

{
    "username": "foo",
    "password": "bar"
}

Then we get a signed token like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJmb28iLCJpYXQiOjE2MDA2MjUzOTd9.05p7hoD3Qma4ShXIVWi0pKBQIv4wqSvEIvuNhaJtens

Once we decode it, we should get all the data in the object returned.

To verify the token, we can use the jwt.verify method. For example, we can write:

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');

const users = {
  foo: {
    username: 'foo',
    password: 'bar',
    id: 1
  },
  bar: {
    username: 'bar',
    password: 'foo',
    id: 2
  }
}

const app = express();
const SECRET= 'shhhhh';

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(express.static('public'));
app.get('/', (req, res) => {
  res.sendFile('public/index.html');
});

app.post(
  '/login',
  function(req, res) {
    const {
      username,
      password
    } = req.body;
    const user = users[username];
    if (user === undefined) {
      return res.status(401).send('invalid user')
    }
    if (user.password !== password) {
      return res.status(401).send('invalid password')
    }

const {
      id
    } = user;
    jwt.sign({
      id,
      username
    }, SECRET, function(err, token) {
      res.send(token);
    });
  }
);

app.get('/secret', (req, res, next) => {
  console.log(req.headers)
  jwt.verify(req.headers.authorization, SECRET, function(err, decoded) {
    if (err){
      return res.status(403).send('unauthorized')
    }
    req.user = decoded;
    next()
  });
}, (req, res)=>{
  res.json(req.user);
})

app.listen(3000, () => console.log('server started'));

We added the /secret route that has a middleware that checks the Authorization header for the token.

Then we pass that into the jwt.verify method to check the token.

The 2nd argument is the same secret string that we used to sign the token.

We need this to do the check properly.

Then once we decoded the string, we return 403 error if there’s an error.

Otherwise, we set req.user to the decoded token object so we can use it in our route.

Then we call next to call the route handler.

If we make a GET request to the /secret route, we should get the user data returned in the response.

Conclusion

We can use the jsonwebtoken package to issue and verify JSON web tokens for authentication.

Categories
Node.js Basics

Node.js Basics — Add 3rd Party Authentication to an Express App with Auth0

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Set Up Our App in Auth0

Before we write our app, we have to set up our Node app in Auth0.

To create our app in Auth0, we log into Auth0, then we go to https://manage.auth0.com/dashboard/us/dev-v7h077zn/applications to go to the Applications page.

Then we click Create Application to create a new application.

Once we did that, we click on Regular Web App, then click Create.

Then we click on Node.js to create our app.

Create the Express App

Once we created our Express app, we can write the following to create our app:

const express = require('express');
const bodyParser = require('body-parser');
const { auth } = require('express-openid-connect');
const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

const config = {
    authRequired: false,
    auth0Logout: true,
    secret: 'a long, randomly-generated string stored in env',
    baseURL: 'http://localhost:3000',
    clientID: 'client id',
    issuerBaseURL: 'https://<domain>.us.auth0.com'
};

// auth router attaches /login, /logout, and /callback routes to the baseURL
app.use(auth(config));

// req.isAuthenticated is provided from the auth router
app.get('/', (req, res) => {
    res.send(req.oidc.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.listen(3000, () => console.log('server started'));

We install the express-openid-connect package to let us add authentication with Open ID.

To install it, we run:

npm i express-openid-connect

to install the package.

We call the app.use(auth(config)); to add the routes for login, logout, and the callback route that’s called after authentication succeeds.

Then we can go to the / route and see if we’re authenticated or not.

We check if we’re authenticated by calling the req.oidc.isAuthenticated() method.

The config object has the clientID, issuerBaseURL, baseURL, and the secret properties.

We can get all them all from the app’s page in our Auth0 account.

issuerBaseURL is the domain that our app is hosted on.

Now when we go to http://localhost:3000/login , we should be able to log in with a Google account.

Getting Logged in User’s Data

To get the data of the currently logged in user, we can write:

const express = require('express');
const bodyParser = require('body-parser');
const { auth, requiresAuth } = require('express-openid-connect');
const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

const config = {
    authRequired: false,
    auth0Logout: true,
    secret: 'a long, randomly-generated string stored in env',
    baseURL: 'http://localhost:3000',
    clientID: 'client id',
    issuerBaseURL: 'https://<domain>.us.auth0.com'
};

// auth router attaches /login, /logout, and /callback routes to the baseURL
app.use(auth(config));

// req.isAuthenticated is provided from the auth router
app.get('/', (req, res) => {
    res.send(req.oidc.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.get('/profile', requiresAuth(), (req, res) => {
    res.send(JSON.stringify(req.oidc.user));
});

app.listen(3000, () => console.log('server started'));

We add the /profile route with the middleware returned by the requiresAuth function to make it available only to authenticated users.

Then the req.oidc.user property has the user data.

Once we logged into the Google account, we should see the data from the /profile route.

Conclusion

We can add 3rd party auth into our Express app easily with Auth0.

Categories
Node.js Basics

Node.js Basics — HTTP

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

HTTP

The http module is a module that comes with the Node.js runtime environment.

We can use it to create a simple HTTP server.

All we have to do is to require the HTTP package by writing:

const http = require('http');
const server = http.createServer();
server.listen(8080, () => {
  console.log( 'Listening on port 8080' );
});

We require the HTTP module and then call the createServer method on the imported module to create our server.

Then we call the listen method on the server object to listen for requests on port 8080.

If we want to to handle requests and return responses, we can use the request and response parameters to get the request data and create the response respectively.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  count += 1;
  response.writeHead(201, {
    'Content-Type': 'text/plain'
  });
  const message = `count: ${count}`;
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

We use the methods in the response object to create the response that we return to the user.

We call the writeHead method with the status code and the response headers that we want to return.

The Content-Type header is set to text/plain so that we can let the client know what the data type of the response is.

201 status means a new object is created.

The response.end method lets us return the response body to the client.

To get request data, we can use the properties of the request parameter.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  count += 1;
  response.writeHead( 201, {
    'Content-Type': 'text/plain'
  });
  const message = `count: ${count}, path: ${request.url}`;
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

to get the path of the URL with the request.url property and return it with the response body.

Routing

Since we have access to the URL that the request is made to, we can do something according to the URL that the user is accessing.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  let message,
    status = 200;
  count += 1;
  switch (request.url) {
    case '/count':
      message = count.toString();
      break;
    case '/hello':
      message = 'World';
      break;
    default:
      status = 404;
      message = 'Not Found';
      break;
  }
  response.writeHead(status, {
    'Content-Type': 'text/plain'
  });
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

to send different responses according to the URL that is given.

If request.url is /count then we return the value of the count with the 200 status.

If request.url is /hello , then we return 'World' with the 200 status.

Otherwise, we return 'Not Found' with a 404 status.

Conclusion

We can create a simple HTTP server with the Node.js’s built-in http module.

Categories
Node.js Basics

Node.js Basics — Handle Complex HTTP Requests

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Complex Routing

It’s easy to do simple routing with our own code with our own HTTP server, but if we want to add more complex routing, then we can use the router module to help us do this.

To use it, we install the router and finalhandler packages by running:

npm i router finalhandler

to install the packages.

Then we can use it to handle requests by writing:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router()
router.get('/', (req, res) => {
  res.setHeader('Content-Type', 'text/plain; charset=utf-8')
  res.end('Hello World!')
})

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We create the Router instance and then call the get method on it to create a GET route to let us handle GET requests to the / route.

The res.setHeader method lets us set the response header.

And the res.end method lets us set the response body.

To accept URL parameters, we can write:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router({ mergeParams: true })
router.route('/pet/:id')
  .get(function (req, res) {
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify({ name: 'tobi', id: req.params.id }))
  })
  .delete(function (req, res) {
    res.end()
  })
  .all(function (req, res) {
    res.statusCode = 405
    res.end()
  })

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We pass in an object to the Router function with the mergParams property set to true so that we can accept URL parameters.

Then we can use the route method to define routes that takes the id parameter.

The :id substring is the URL parameter placeholder for the id parameter.

Then we call res.setHeader to set the header.

And we use the req.params.id property to get the value of the id URL parameter.

We set the res.statusCode property to set the response status code.

The delete method lets us define a route to handle a DELETE request.

We can also add a middleware that runs before our routes run.

For example, we can write:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router({
  mergeParams: true
})
router.use(function(request, response, next) {
  console.log('middleware executed');
  next(null);
});
router.route('/pet/:id')
  .get(function(req, res) {
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify({
      name: 'tobi',
      id: req.params.id
    }))
  })
  .delete(function(req, res) {
    res.end()
  })
  .all(function(req, res) {
    res.statusCode = 405
    res.end()
  })

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We call the use method with a function. This function is called before any route handler is called.

Therefore, we should see 'middleware executed' string logged in the console.

The next function lets us call the route handler.

Conclusion

We can create more complex route handlers for our HTTP server with the router package.