Express 4.x OAuth and Local Authentication with Passport.js: Pt 1

muyiwa akin-ogundeji
27 min readDec 26, 2015

--

In today’s article, we will pull together a number of previously reviewed concepts as well as explore new ground as we cover OAuth and Local Authentication in Express 4.x using Passport.js.

The full code can be found at https://github.com/oakinogundeji/express-4x-localnOAuth .

So, what do we want to achieve today?

We want to build a simple Express 4.x app which allows users to signup/login using any of Local auth, Facebook or Twitter. A logged-in user can link any of the other accounts to his/her profile in order to access certain features our app makes available — specifically pulling in the latest Twitter activity on the user Twitter account and the latest posts which the user made on Facebook.

Much of the foundation for what we’re going to cover today has already been laid in a previous article (Local Authentication with Express 4.x and Passport.js), other important concepts especially for the frontend (using Vue.js) have also been covered previously (MY VUE ON MVVM). Nevertheless, for the sake of completeness we’ll review the most important concepts as we build our app.

TECH STACK

We will use the following tech stack in building this app:

  1. Frontend: Vue.js (including vue-resource) , Bootstrap
  2. Backend: Node.js, Express.js, MongoDB/Mongoose.js, Passport.js (including passport-local, passport-facebook and passport-twitter)
  3. Feature modules: twit, facebook-node-sdk
  4. Tooling: npm (task runner), browserify (including the ‘partialify’ transform)
  5. Testing: mocha, should, supertest

These are the main packages we will use, everything used is of course listed in ‘package.json’ as shown below:

Lets briefly review some points of interest in the preceding file.

  1. Notice the ‘browserify’ field? This is important to allow inclusion of the ‘partialify’ transform which allows us to ‘require’ HTML, CSS and other files. This makes creating templates relatively trivial.
  2. Because we’re using npm as our task runner, we need to create a ‘scripts’ field within which we define the tasks npm should run. e.g ‘npm run watch’ will invoke ‘watchify’ and cause it to build the bundle file for the frontend by pulling in all dependencies beginning from ‘app.js’ and outputting them as ‘main.js’ after passing it through the ‘partialify’ transform (more on this later).

END PRODUCT

It’s a good idea to have a ‘vision’ for what we want to achieve, the following screenshots keep us focused on the intended result:

Landing page

The picture above is the landing page for the app, it simply welcomes the user and offers several means of accessing the app.

login page

The ‘login’ page has options for the user to login with a local account (i.e. email plus password) or via Oauth using Facebook or Twitter.

signup page

The ‘signup’ page also offers options for signup via local account or OAuth.

custom error page

There is a custom error page which is displayed if there’s any internal server error i.e. HTTP 5xx status codes.

dashboard with twitter signin

Assuming the user signed in or logged in via Twitter, the dashboard page displays a welcome message as well as options to link any presently unlinked accounts to the user’s profile — in this case, facebook and loacl accounts.

twitter profile

A logged in user has access to several ‘profile’ pages which present information about the user (dained via OAuth’ and make some features available e.g. in this case ‘Get recent timeline activity’.

twitter profile with timeline activity

If the user clicks on the ‘Get recent timeline activity’ button, the 10–15 most recent tweets on his/her timeline will be displayed.

unlinked facebook profile

For the signed in user (via Twitter) who hasn’t linked the Facebook account to the profile, there’s nothing to display. However, if the user does link the Facebook account, then he/she has access to info from facebook as well as 10–15 most recent posts, which the user made as shown below:

facebook profile linked
facebook profile with posts

The same holds for the ‘local’ account:

unlinked local profile
linked local profile

By default, the current user profile is the ‘local’ profile (if it exists), so for the user with all 3 accounts linked, the profile page looks like the following:

profile page with all accounts linked

Notice that the ‘Link your other accounts to your profile’ message no longer shows.

Whew… with that behind us, lets move to planning the app so the end result matches our expectations.

APP FUNCTIONALITY

We want our app to perform the following functions for the user:

  1. An unauthenticated user can’t access the ‘protected’ part of the app i.e. the ‘dashboard/profile’ area. Any attempt by an unauthenticated user to access this portion should trigger a redirect to ‘/login’.
  2. A user has 3 options for login/signup — local, facebook or twitter.
  3. A loggedin user (via any of the previous 3 options) can choose to link any of the other accounts to his/her profile in order to access desired features.
  4. To protect the user against multiple linking attempts, any account which has been successfully linked to the user’s profile is removed from the list of available accounts to be linked. When all 3 accounts have been linked, the message inviting the user to link accounts is no longer displayed.
  5. To prevent unnecessary server calls, a logged in user who hasn’t linked other accounts will be able to access the profile pages for the accounts but no info or features for that profile will be displayed.
  6. If the user logs out, the session is destroyed and the user is redirected to the ‘home’ page.
  7. The photo displayed on the user’s profile will be the first one available from either Twitter or Facebook (defaults to Twitter).

With the preceding in mind lets begin to build our app starting by developing the app structure.

APP STRUCTURE

If you’ve seen any of my previous work, you’ll know that there’s a pattern to the way i structure my code. I like to have a server.js module which is the entry point to the app. This module may be built on either the native Node ‘http’ or ‘https’ modules.

Then i like to have an app.js module which exposes the ‘Express’ app server. This module coordinates much of the app functionality e.g. dBase connection, routes etc. I also like to separate routes/routing from the main Express app and to mount these router mini-apps to specific mount point is the main Express app.

I also like to have a config directory with a config.js module which exposes configuration variables such as API keys, environment specific settings etc to the Express app by reading the value of the ‘process.env.NODE_ENV’ variable and pulling in the appropriate ‘.json’ file depending on whether the app is running in ‘development’ or ‘production’ mode.

I also like to build out my models in dedicated modules and expose these models to the Express app via module.exports.

With that overview behind us, lets examine the directory structure for this application:

/
|- server.js
|- app.js
|- package.json
|- config
|- config.js
|- development.json
|- production.json
|- passport.js
|- models
|- users.js
|- userUtilities.js
|- public/js
|- components
|- facebook
|- index.js
| - template.html
|- local
|- index.js
|- template.html
|- nav
|- index.js
|- template.html
|- profile
|- index.js
|- template.html
|- twitter
|- index.js
|- template.html
|- routes
|- facebook.js
|- root.js
|- twitter.js
|- test
|- logintest.js
|- userAPItests.js
|- usertests.js
|- utils
|- isLoggedIn.js
|- views
|- pages
|- dashboard.ejs
|- errors.ejs
|- index.ejs
|- login.ejs
|- signup.ejs
|- partials
|- footer.ejs
|- head.ejs
|- header.ejs
|- layout.ejs

Ok, so that’s our directory structure, notice the ‘ /public/js/components’ portion — this portion allows us to take advantage of the Node module system to develop reusable components for the clientside app.

Having defined the directory structure, lets go ahead to build out the backend.

BACKEND OVERVIEW

The backend of our app will include the following portions:

  1. Base app: This bootstraps the app and involves the server.js and app.js modules.
  2. App configuration: This module provides app-wide configuration and API key values. This involves all the modules within the ‘config’ directory. We could have simply created an ‘index.js’ file inside the ‘config’ directory and then exposed the desired module functionality through this file, but for now, we’ll simply export each ‘sub module’ independently of the others.
  3. Data Models: These modules facilitate structured access to the dBase to perform CRUD operations on the data which the App consumes and generates. The modules involved are within the ‘models’ directory.
  4. Routes: These modules implement what may be thought of as the ‘Controller’ portion of an MVC structure. Our architecture is not strictly MVC, more like MV* and that is in order to make it much easier for the frontend to consume API endpoints and present an interface to the user. This App will use 3 route groups — a) the base routes which handle access to the landing page, local authentication and access to the protected portion of the app (i.e. ‘user dashboard/profile’) b) the facebook route which allows a logged in user with a facebook account to retrieve recent posts made by the user on facebook and c) the twitter route which provides the same functionality for the user as the facebook route.
  5. Views: These render the interface of the app to the user. The views are developed using the ‘ejs’ templating language and they take advantage of ‘layouts’ and ‘partials’ to reduce repetitive coding of immutable portions of the views.

With the backend overview in hand, lets begin by examining what goes into the config module.

CONFIG DIRECTORY

The config module consists of 3 files initially — config.js, development.js and production.js. We will later add passport.js to this directory when we implement authentication.

The purpose of this directory is to provide a single point of reference for app-wide configuration of variables which determine the behaviour of this app. Let’s begin by examining config.js

CONFIG.JS

As can be seen, this is a one line module, it simply examines the value of ‘process.env.NODE_ENV’ and determines which ‘.json’ file to load, the default is ‘development.json’.

DEVELOPMENT.JSON

This file holds enviroment variables and API key values for the ‘development’ environment.

PRODUCTION.JSON

This file provides the same function for the app when in ‘production’ mode as development.json performs in ‘development’ mode. These 3 files work together to make it easy for us to define how the app should behave under different circumstances, this system makes it easy to modify, maintain and extend our app.

At this point, we have one of 2 choices — a) build the base app, create a test route and then test that everything is working properly or b) build the data model first before developing the base app.

I like to follow option a since i want to confirm as quickly as possible that the app is setup properly. So we’ll examine the base app next.

BASE APP

The base app portion consists of server.js and app.js. All app functionality is pulled into app.js and then exposed to server.js via module.exports. In Node, a http/https server requires a request handler which handles request connections from the client. When Express is used with Node, the Express app is passed to the http server as the request handler.

Therefore we begin with app.js.

APP.JS

The preceding module is the completed app.js for our app. Lets examine the module to understand what it is doing now and will do when other parts of the app are built out.

The ‘Module Dependencies’ section pulls in all the dependencies which this module requires to function as we intend it to. Notice line 9 — this pulls in the already created ‘config.js’ module.

The ‘Module Variables’ section creates module specific ‘global’ variables which are exposed to various parts of the Express app, on line 25 we declare the ‘port’ which the app will listen on — the default value is 3030 (‘for a development server’).

Lines 26–28 declare useful variables derived from the ‘config.js’ module. Because this app uses a ‘session store’ based session management system, line 29 declares the ‘sessStore’ variable which will be initialized later in the module. Note also how we first declare the ‘session’ middleware (line 12) before passing it to the session store instance i.e. ‘mongoStore’’ (line 14).

Since our dBase is MongoDB, we pull in ‘Mongoose’ as the ODM on line 13. Mongoose will be passed the dBURL declared as a module variable and will be responsible for connecting to the dBase whenever the app is started. I trust you’re familiar with the other modules used as dependencies (path, bParser, logger) — ejsLayouts makes it possible to use layouts with ejs in Express 4.x.

Lines 31–33 declare the routes we will use in the app and they’re pulled in from yet to be created modules.

The next portion of the app is ‘Config & Settings’, in this section we perform app-wide configuration such as setting the port, operating environment (i.e. development, production etc), mapping the ‘views’ directory to the location we’ve created for it, configuring the ‘view engine’ as well as setting the app to use ‘layouts’. We also pull in the ‘clarify’ module which makes it much easier to trace errors in Node terminal printouts.

After configuring the Express app, we setup the dBase connections by using built-in mongoose methods. We also setup the ‘session store’ so that it uses the same dBase but different ‘collection’ as the base app, the ‘touchAfter’ option ensures that any unmodified session is updated to the session store after 24 hours, this reduces the dBase calls and makes our app more performant.

The next section sets-up the ‘middleware’ stack. We use the ‘logger’ in ‘dev’ mode, setup body-parser to decrypt JSON and POST bodies from submitted forms, and then we configure the ‘session’ middleware. Because the session store “connect-mongo’ implements the ‘touch’ interface, we can safely set the ‘resave’ option to be ‘true’ (this is why we defined the ‘touchAfter’ option when setting up the session store) — after these middleware, we ‘use’ ejsLayouts and setup the Express app to serve static pages by mapping the path to the directory which contains static pages via ‘express.static’ middleware.

The next section ‘Routes’ contains the ‘mount points’ for the 3 router mini apps we will be using — one to handle basic routes, one to handle facebook specific routes and the last to handle twitter specific routes. Notice that we also created a special route to test the app i.e line 86.

After doing all the preceding work we create a custom error handler and the export the module.

Now lets examine server.js

SERVER.JS

In this module we declare dependencies as usual (the Express app and the Node http server), create a http server instance and pass the Express app to it as the request handler (line 12), we extract the ‘port’ and ‘env’ variables from the Express server (lines 18–19) before binding the http server to the port and listening for requests (lines 23–26). Finally we ensure that the server module can be exported (e.g. if we need to unit test) by creating a simple ‘if’ block which checks the ‘require.main’ object to see whether or not the server module is being used as the ‘main’ module (which would be the case in most environments except testing).

Now that this has been done, we can start the app by typing ‘npm start’ — however note that because required modules such as the routes haven’t been built out, it’s best to comment them out at this stage or wait till the entire backend has been built before running the app.

Having developed the config modules and the base app modules, we turn our attention to the data models.

DATA MODELS

The data models provide a structured way for the app to perform CRUD operations using data from the dBase and input from the user. The data models we will use consist of the ‘users.js’ and ‘userUtilities.js’ modules.

USERS.JS

Due to the ‘singleton’ pattern employed when creating packages like ‘mongoose’, the mongoose instance used in this module is the same one which is used to create the dBase connection in the Express app. As usual the module starts by pulling in module dependencies- in this case mongoose and bcrypt-nodejs.

The ‘bcrypt’ module allows use to safely store user passwords in our dBase by salting and hashing the plain text passwords before storage.

Notice the structure of the ‘UserSchema’ — there are 2 main parts local and social. While ‘local’ defines the structure for a user object created via local auth, social defines the structure for a user object created via OAuth.

Notice also that while ‘local.email’ has a ‘unique’ key, none of the keys are defined as ‘required’ — the reason is that if a key is set to required and the user object is not created using that key, mongoose will throw a validation error. So when there’s to be a mix of local/social auth, it’s best not to require any key although it’s a good idea to make the ‘local.email’ or ‘local.username’ key unique.

After defining the user schema, notice the schema methods — think of schema methods like Javascript constructor methods i.e. methods which any object created from the constructor (in this case schema) has access to via inheritance. We define 2 schema methods — one to encrypt a plaintext password before storage and another to ‘decrypt’ the password in order to compare the ‘hash’ values for user authentication.

Lastly, we create the model and export the module.

USERUTILITIES.JS

Now that the main user model has been developed, we create a set of helper functions in the ‘userUtilities’ module to make it easy for the app to perform CRUD operations on the user object. The sole module dependency is the ‘users.js’ module and the module exports an object which exposes useful helper methods.

Having created the model. we return to the ‘config’ directory to build the passport authentication module.

PASSPORT.JS

This is the complete passport.js module to handle both ‘authentication’ and ‘authorization’. We have covered the mechanism of passport authentication in a previous article. However, we will briefly review the salient points.

  1. The passport.initialize()/passport.session() middleware are not used here but will be used within the root routes module in order to allow passport to intercept an incoming request connection to check whether or not the user is logged into the session (i.e. passport.initialize() this is explained below) and then for a new user who has been authenticated, passport creates a passport session for that user (i.e. passport.session()).
  2. passport.serializeUser() and passport.deserializeUser() are used to retrieve a user object from the session and to save the user object back into the session. This functionality is ‘turned on’ by passport.initialize().
  3. passport.authenticate() is route specific middleware used in the root router module to implement local and OAuth authentication for the appropriate routes.

Having briefly reviewed how passport works, lets examine the module.

As usual the first thing we do is to pull in module dependencies. Apart from the actual passport module, the 2 other dependencies are the ‘config.js’ module and the ‘user model’ module.

The next major step is to pull in passport’s local, facebook and twitter strategies (lines 15–17), after that we declare the required API keys and callbacks to implement OAuth authentication (lines 18–23).

The first major module configuration is setting up the passport.serializeUser()/passport.deserializeUser() methods. This brings us to the ‘Strategies’ section. Local Authentication has been covered in depth in the previous article so we focus here on local Authorization.

Note first that the structure for the ‘local-signup’ strategy is different from that in the previous article. Notice especially the ‘if(!req.user)’ block and the succeeding ‘else’ block. Let’s examine the ‘logic flow’ to understand what’s happening here.

  1. When the ‘local-signup’ strategy is triggered, it searches for declares that the value expected by passports’ ‘usernameField’ will be satisfied by the ‘email’ field retrieved from req.body.email, while the value expected by the ‘passwordField’ is satisfied by req.body.password.
  2. Next the ‘req’ object is passed to the callback along with the values for the ‘email’ and ‘password’ parameters as well as the special ‘done’ object. The use of ‘process.nextTick’ is a Node idiom which ensures that the enclosed function is executed during the next cycle of the ‘event loop’ right before any I/O takes place. This idiom ensures that the execution flow is always ‘async’.
  3. The ‘if(!req.user)’ block checks if the ‘req’ object does not have a ‘user’ property — this ‘user’ property is appended to the ‘req’ object by passport.js whenever a user has been authenticated and serialized to the current session. In essence this condition is ‘saying’ that if a user does not exist at present then take the actions within the block. The ensuing action is to use the ‘user model’ module to find a user with a ‘local.email’ property whose value is equal to the value of the ‘email’ object passed to passport. Since the ‘email’ field of a user is unique, there can be only one such email in the dBase, so if that email is found it means one of 2 things — a) either that the ‘new’ user already exists and thus should log in rather than sign up or b) the user has made a mistake in the email value. Either case an error message is returned. However, if the user does not previously exist, then the user is created.
  4. The ‘else’ block on the other hand is activated if the user is already serialized to the session either through logging in with facebook or twitter; if such is the case, then a new ‘local’ profile is created for that user and associated with the presently logged in user. Note that passport provides an ‘account’ object for this purpose, but i prefer this implementation as it’s clearer for me to reason about.

Step 4 above is required for Authorization which is the process of linking available profiles of an already authenticated user to his account in the app. I encourage you to review the aforementioned article as well as the passport documentation if further clarification is required.

We’ll skip ‘local-login’ because nothing new happens here, we’ll instead examine the ‘facebook’ strategy as a template to understand both the ‘twitter’ strategy and any other passport strategy we may wish to implement.

The Facebook Strategy:

The first thing to understand is that using any OAuth provider requires that we register our app with that provider, what this means is that we need to create an app (even a sample app) and then acquire API keys and other credentials form the provider e.g. facebook in order for our app to successfully use the provider for Authentication/Authorization and to use other features the provider makes available. In this case that means we go to facebook devs and create an app which we register.

Once our app is registered we have access to 1) app ID and 2) app Secret -which are used to access facebook, we also need to provide a ‘callback URL’ of the form shown in ‘development.json’.

With these things done, we can safely configure the facebook strategy for use in passport for both authentication and authorization.

Note that in the ‘FBStrategy’ i.e. facebook strategy, there are 5 keys which passport requires that we provide values for. 1) clientID: this maps to the facebook app ID 2) clientSecret: this maps to the facebook app secret 3) callbackURL: this maps to the facebook callback URL 4) profileFields: these are the specific fields whose values we want to retrieve from the user profile object which facebook returns to passport upon successful authentication or authorization. In this case we want the user’s facebook id (id), user’s display name on facebook (displayName), the email address the user is registered with on facebook (emails) and any profile photo which the user has on facebook (photos), lastly 5) passReqToCallback: is set to ‘true’, this ensures that the ‘req’ object is passed into the callback function of the FBStrategy object and provides us access to the user if already authenticated and serialized into the session by some other means e.g local or twitter.

The rest of the ‘logic flow’ is essentially the same as for ‘local-signup’ with the difference being the particular objects available within the callback i.e the accessToken, refreshToken and profile objects.

As you may already have guessed, it’s through the profile object that we are able to access the requested profile fields used to create a user’s facebook profile in the app. The function of the ‘accessToken’ is to authenticate any requests which our app makes to facebook on the user’s behalf, specifically access to the user’s post. THis same logic holds for the twitter profile and any other OAuth provider we may wish to use with passport.

After setting up the strategies, the passport module is exported and ready to use in other parts of the app.

We’re now faced with 2 choices — views or routes? I believe that we should build the routes first as if this is done, we can test that the endpoints function as expected and then more confidently build out the views. So next stop… routes!

ROUTES

In our app, we create 3 router modules 1) the base/root app router: this handles all routes from landing page, login/sign up authentication and serving the ‘dashboard’ interface which we create as a mini SPA. 2) the facebook router which makes it possible for the user to retrieve the most recent facebook posts and 3) the twitter router which does the same for the user for the twitter timeline.

ROOT.JS

As usual we first pull in module dependencies. In this module the dependencies are Express, the already configured passport module and the ‘user utilities’ module.

Next we declare module variables — notice the ‘isLoggedIn’ function pulled in from the ‘isLoggedIn’ module, this function serves as a guard to filter access to protected portions of our app — specifically the ‘dashboard’ SPA portion. We also create helper methods which allows an ‘Admin’ to review user info for the app.

Next section handles the passport middleware — .initialize()/.session() which we have already discussed. The next section deals with the base routes.

Notice line 38 which exposes the ‘router.route’ idiom, this idiom allows one to chain multiple http methods acting against a common route. In this case ‘GET’ and ‘POST’ operations acting against the ‘/login’ route. As you may know, ‘GET’ is responsible for rendering the ‘login’ form while ‘POST’ handles the form submission.

The function of ‘passport.authenticate()’ has already been discussed so we won’t review it. THe next interesting portion begins from line 82.

At this stage, the user has been successfully authenticated and gained access to the protected ‘dashboard’ SPA route. Before this route is rendered we ensure that several useful variables are made available to the user — specifically required info from the user’s profile, and other helpful methods e.g currentProfile and linkStatus. With this preparation, we can successfully render the dashboard SPA and subsequent interactions are managed on the client side via the SPA.

Line 146 introduces the ‘/logout’ route which ensures that 3 actions happen in succession 1) the user is first ‘logged out’ of the passport session 2) the user’s session information stored in the session store is erased and 3) the user is redirected to the landing page.

Lines 152–167 handle user login via facebook or twitter. Since we used facebook as an example in the section on passport, we’ll continue to use facebook as we examine the OAuth routes.

On line 160, we create a ‘GET’ handler which responds to the user clicking on a button/link on the ‘login’ or ‘signup’ page in order to login/signup via facebook or some other OAuth provider. passport.authenticate() is triggered and this searches for the ‘facebook’ strategy (NB ‘facebook’ is the default name for the facebook strategy in passport) and also seeks extended permission to access the user’s posts via the ‘scope’ key.

As has been explained in the previous article, passport.authenticate() works hand in glove with the provided strategy and hands-off control to the strategy. In this case, all passport.authenticate() does is follow the ‘/auth/facebook’ link to contact facebook providing any additional permission requests via ‘scope’ — if the user authorizes the app to access the user’s facebook info, then line 162 is triggered.

Line 162 causes passport.authenticate() to hand control to the facebook strategy and the facebook strategy does its thing. Upon successful creation of the user, the facebook startegy returns control to passport.authenticate() which then redirects the user to the ‘/dashboard’ route (line 164), if there’s any failure by the facebook strategy to successfully create a new facebook profile for the user, the user is redirected to the ‘login’ page (line 165). This same logic holds for the ‘twitter’ routes and any othe OAuth provider we may use with passport.

Now lets examine how other profiles are connected/linked to an existing user’s account.

We begin with line 170 which ‘links’ a ‘local’ account for a user who perhaps signed in via facebook or twitter. When the user clicks on the link/button to ‘connect/link’ the ‘local’ profile to the account, line 171 is triggered and it simply renders the ‘signup’ page so the user creates a ‘local’ account by signing up locally.

Line 175 begins the ‘POST’ handler which handles the form submission. Notice line 176 — passport.authenticate() is called, why? Because local user authentication does not require any 3rd party interface, thus passport.authenticate() is used to trigger the ‘local-signup’ strategy which creates a local user using the ‘else’ block (this has been explained in the passport section).

Line 193 begins the linkage of an OAuth account i.e. facebook. Notice the route is ‘/connect/facebook’ rather than the previous ‘/auth/…’ route! Note also that passport.authorize() is used (line 194) rather than passport.authenticate(). As explained above, since a 3rd party OAuth provider service is involved and the user already has a profile and is also already currently in the session, we require authorization to link the OAuth accounts rather than authentication to create a new one. From lines 194–201 the mechanism of authorization is essentially the same as that of authentication with the exception of internal passport processes triggered by passport.authorize().

Lines 213–226 handle the ‘user API’ routes which provide an ‘admin’ access to the list of users registered for the app. Nothing special happens here, we simply leverage the helper methods to perform CRUD operations against the users in the dBase.

Lastly we export the router module and it is now available for mounting on the mount point provided for it in app.js. Next we examine the facebook router.

FACEBOOK.JS

As usual we begin by pulling in module dependencies, the 2 external dependencies are the ‘config’ module as well as the excellent ‘facebook-node-sdk’ npm module which provides features allowing us to leverage the facebook ‘Graph API’ to access user data.

The module variables are the appID and secret variables pulled in from ‘config’ module. The module middleware is a configured instance of the ‘facebook-node-sdk’ module.

We define a single route handler which responds to a request to ‘/’. Why is the route ‘/’? Isn’t ‘/’ the root route for the app? Well if you go back to app.js (specifically line 92) you’ll notice that the facebook router module is mounted at ‘/facebook’ — this means that any request which begins with ‘/facebook’ is passed to the facebook router, thus we can safely use the ‘/’ route which corresponds to ‘/facebook’ in this case.

The first thing we don within the handler is confirm that the requester actually has a facebook profile on the app (line 31) although we also take some steps to prevent such an action in the SPA (more on this later). If the user has a facebook profile associated to his/her account on the app then in line 32 we configure the facebook graph API endpoint URL using the user’s facebook ID to access the user’s most recent post. If any error occurs, this is handled else we respond with the data encoded as JSON (line 37). If the user doesn’t have a valid facebook profile associated with his/her account, then the ‘else’ block is triggered and the user receives a warning message.

Lastly, the module is exported and can be used within the base app. Next we examine the twitter router.

TWITTER.JS

As usual we begin by pulling in module dependencies, this time we use the excellent ‘twit’ module to serve as the twitter client. We also pull in the ‘config’ module.

In lines 18–32 we declare module variables, the consumer_key etc are pulled in from the ‘config’ module, we also create and instantiate a ‘client’ variable setting it to ‘null’ initially. This object is used to access the twitter API. Next we declare a ‘connectToTwitter()’ function which actually configures an instance of the ‘twit’ module and assigns its value to the previously created ‘client’ object.

In line 37, we activate the twitter client and are subsequently able to use it within the route handler (lines 42–73). The route that is handled is ‘/statuses/home_timeline’. However, the ‘client’ object needs to actually hit the ‘statuses/home_timeline’ endpoint on the twitter API, to make this possible we use lines 45 -46 to extract the portion we are interested in from the route passed to the handler (req.route is an Express request object property which returns the currently matched route i.e. ‘/statuses/home_timeline’ — while the ‘.path’ property of req.route returns that actual route as a string). In lines 47–48 we configure a ‘params’ object with the user’s twitter screen name (i.e. twitter handle).

From line 50, we execute the ‘client’ object passing in the configured options, if there’s an error we throw it else we handle the returned data from line 54. We extract the portions of the data we’re interested in by creating an array and populating it with the data objects we wish to present on the frontend. Then we return the response configured as JSON.

Note that the preceding takes place within an ‘if’ block which checks that the user making the request has a twitter profile associated with the user account else we respond with an error message (line 71). Having successfully configured the twitter router, we export the module so it too can be used in the base app.

This brings us to the last major portion of the Backend — the Views.

VIEWS

The views are responsible for formatting and presenting data from our app to the user either directly (server rendered views) or via the SPA. The ‘views’ portion of our app consists of 3 main elements 1) the base ‘layout’: this is important as it allows us to define a general structure/framework for rendering the views which is common to all the template files we will use. This is implemented in ‘layout.ejs’ (for your information, line 45 in app.js mapped the ‘layout’ functionality of Express to ‘layout.ejs’ the extension was omitted because we had previously (on line 44) configured the ‘view engine’ setting it to render all ‘.ejs’ template files). 2) partials: A ‘partial’ defines the structure for some layout element e.g ‘header’ which is repeated in all the template files. The partials we will use are a) head (which defines the HTML head element) b) header (which defines the HTML header element) and c) footer (which defines the HTML footer element). 3) pages: these are the actual template files which represent the various pages we will render from the app server i.e. landing page, login, signup, dashboard as well as the custom error page.

We won’t examine every single view file, but we’ll go over layout.ejs (layout), head.ejs (partial), signup.ejs (page) and dashboard.ejs (page).

LAYOUT.EJS

The layout file defines the overall structure for the template files. Lets examine some important portions of the layout. Notice lines 3–6 which define the <head> element. On line 4 we ‘include’ the ‘partials’ file representing the main content of the ‘head’ element. However, on line 5 we do something really cool, we make provision to conditionally include content from ‘dashboard head’ by using the ‘defineContent()’ method of ‘express-ejs-layouts’ module. Thus we can quite easily conditionally load optional content whereever we choose in the layout without affecting the normal operationg of othe views. This same process is repeated on line 13. Essentially every template ‘page’ will have this basic structure and include content from the various partials while rendering it’s own content within the ‘<%- body%>’ section of the layout.

HEAD.EJS

head.ejs simply defines the content of the <head> element — charset, title, css links and a <style> element.

SIGNUP.EJS

signup.ejs defines the structure for the ‘signup’ form. Notice lines 3–5, this is ‘ejs’ code to conditionally render a block of HTML in this case, if there is an error message represented by the ‘errMsg’ variable it is rendered. login.ejs also has this conditional code block thus rather than repetitively defining the ‘errMsg’ variable for each response, we leverage a built-in Express capability called ‘locals’. locals allow us to define variables from the Express app which are made available to the templates rendered as views. The 2 types of locals are response locals which are specific to a particular ‘req-res’ cycle and application locals which are available across the app. Thus in app.js (line 34) we create an app-wide ‘errMsg’ local which is available to all templates which include the ‘errMsg’ variable.

Notice also lines 15 and 17. These create buttons which make it very easy for a user to signup via facebook or twitter. These buttons are the starting point for the OAuth authentication process.

DASHBOARD.EJS

dashboard.ejs represents the SPA portion of the app. A user who successfully reaches the ‘/dashboard’ route has access to the SPA which is responsible for displaying the user’s info as well as providing access to both facebook posts and twitter timeline. Let’s examine what is available through this view.

Notice line 2, this provides the content for the conditional block defined in layout.ejs. Because facebook does some funny stuff to the URL when it responds to the OAuth request, we use lines 5–7 to rectify the interfernece and ensure that a nice ‘#!’/’#’ is displayed in the nav bar rather than ‘#_=_’.

Line 10 begins the main SPA content. Lines 13–19 define the structure of the Vue.js based SPA enclosed within a <div>, line 20 is simply informational and allows us to see how some values change in the SPA, it may be safely commented out or deleted (more on this later).

The next major portion of the SPA is the content enclosed within ‘script’ tags i.e. lines 24–91. Because there’s no direct way to pass values from the Express app into the Vue.js app, we use the convenient fact that we can safely pass variables to the template from the Express app and if those variables are ‘encapsulated’ within ‘script’ tags, the browser will not try to execute them. Lines 24–71 declare all the variables we wish to pass into the template from the backend… but now we’ve got a problem, while we’ve passed in the variables we want to use, how do we actually access them inside the Vue.js app? The solution is to leverage on the fact that in the browser, all javascript code is executed within ‘global’ scope. Therefore in lines 72–91, we use ‘namespacing’ to create a global ‘appUserData’ object as a property of the ‘windows’ global object and this makes these variables safely available to the Vue.js app.

At this point, we have reached the border between the backend and the frontend, the next post will examine the frontend namely the Vue.js SPA which leverages the Express backend to create a fullstack javascript application.

Whew…

This has been quite a long read and i thank you for staying with me, please leave any comments below or reach out to me for any clarification.

Part 2 is available here.

--

--